Fix #40
flavien's git/Projet_JAVA_P2P_STRI2A/pipeline/head This commit looks good Details
flavien's git/Projet_JAVA_P2P_STRI2A/pipeline/pr-master This commit looks good Details

pull/76/head
Louis Royer 4 years ago
parent 275eb165b1
commit 1355ef14b1

@ -0,0 +1,409 @@
package clientP2P;
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.StandardOpenOption;
import java.nio.file.StandardCopyOption;
import exception.LocalException;
import exception.RemoteException;
import localException.SocketClosed;
import localException.ProtocolError;
import localException.InternalError;
import localException.TransmissionError;
import localException.SizeError;
import localException.VersionError;
import remoteException.EmptyDirectory;
import remoteException.EmptyFile;
import remoteException.VersionRemoteError;
import remoteException.ProtocolRemoteError;
import remoteException.NotFound;
import remoteException.InternalRemoteError;
import remoteException.NotATracker;
import protocolP2P.HashAlgorithm;
import protocolP2P.HashResponse;
import protocolP2P.HashRequest;
import protocolP2P.Payload;
import protocolP2P.FilePart;
import protocolP2P.LoadRequest;
import protocolP2P.ProtocolP2PPacket;
import clientP2P.ClientDownloadPart;
import tools.HostItem;
import tools.Logger;
import tools.LogLevel;
import tools.ServeErrors;
/** Class to download file
* @author Louis Royer
* @author Flavien Haas
* @author JS Auge
* @version 1.0
*/
public abstract class ClientDownload extends ServeErrors implements Runnable {
protected List<HostItem> hostList;
protected String filename;
protected byte[] hash512;
protected List<ClientDownloadPart> sockList = new ArrayList<ClientDownloadPart>();
protected List<Long> offsetsToAsk = new ArrayList<Long>();
protected List<Long> offsetsPending = new ArrayList<Long>();
protected boolean stop;
protected long size;
protected static final long MAX_PARTIAL_SIZE = 4096;
protected String partsSubdir;
protected String dirStorage;
protected boolean success = false;
protected Logger logger;
/** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage
* @param filename name of file to download
* @param hostList list of servers
* @param partsSubdir directory to store .part files
* @param dirStorage directory to write assembled file
* @param logger Logger
*/
public ClientDownload(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;
}
/** Success getter.
* @return true when file have successfully been reassembled.
*/
public boolean getSuccess() {
return success;
}
/** Getter for hash512sum
* @return hash512sum
*/
public byte[] getHashSum512() {
return hash512;
}
/** Stop threads */
protected void stopTasks() {
for(ClientDownloadPart c : sockList) {
try {
c.setStop();
} catch (InterruptedException e) {
writeLog(e, LogLevel.Error);
}
}
}
/** Asks thread to stop
*/
public void setStop() {
stop = true;
}
/** Assign tasks randomly to threads.
* @throws InternalError
*/
protected void assignTasks() throws InternalError {
Random rand = new Random();
for(long offset : offsetsToAsk) {
try {
sockList.get(rand.nextInt(sockList.size())).assignTask(offset);
offsetsPending.add(offset);
System.err.println("Assigned task "+ offset);
writeLog("Assigned task "+ offset, LogLevel.Info);
} catch(InterruptedException e) {
writeLog(e, LogLevel.Error);
throw new InternalError();
}
}
offsetsToAsk.removeAll(offsetsPending);
}
/** Create a clientDownloadPart
* @param filename name of the file to download
* @param hostItem Hostitem of the server
*/
protected abstract ClientDownloadPart createDownloadPart(String filename, HostItem hostItem);
/** Starts threads for each server in hostList.
*/
protected void initThreads() {
for(HostItem hostItem: hostList) {
sockList.add(createDownloadPart(filename, hostItem));
}
for(ClientDownloadPart c: sockList) {
Thread t = new Thread(c);
t.start();
}
writeLog("Threads initialized", LogLevel.Info);
}
/** Remove tasks from failed threads. Update done status.
* @throws InternalError
*/
protected void checkTasksStatus() throws InternalError {
try {
synchronized(this) {
this.wait();
List<ClientDownloadPart> sockListCpy = new ArrayList<>(sockList);
for(ClientDownloadPart c: sockListCpy) {
if (c.hasFailed() == true) {
sockList.remove(c);
offsetsPending.removeAll(c.getFailed());
offsetsToAsk.addAll(c.getFailed());
}
try {
offsetsPending.removeAll(c.getDone());
} catch (InterruptedException e) {
throw new InternalError();
}
}
writeLog("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending", LogLevel.Info);
if (offsetsToAsk.isEmpty() && offsetsPending.isEmpty()) {
stop = true;
}
if (sockList.size() == 0) {
logger.writeUDP("No thread working", LogLevel.Error);
throw new InternalError();
}
}
} catch (InterruptedException e) {
throw new InternalError();
}
}
/** Get hashsum from server.
* @param hostItem server to ask hash
* @return hash512sum
* @throws InternalError
*/
protected byte[] getHashSum512(HostItem hostItem) throws InternalError {
byte[] hash;
HashAlgorithm[] hashesAlgo = new HashAlgorithm[1];
hashesAlgo[0] = HashAlgorithm.SHA512;
ProtocolP2PPacket<?> d = createProtocolP2PPacket(new HashRequest(filename, hashesAlgo));
try {
d.sendRequest(getHostItemSocket(hostItem));
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 {
hash = ((HashResponse)pHash).getHash(HashAlgorithm.SHA512);
}
} catch (EmptyDirectory e) {
writeLog(e, LogLevel.Error);
hash = new byte[0];
} catch (NotFound e) {
writeLog(e, LogLevel.Error);
hash = new byte[0];
} catch (LocalException e) {
writeLog(e, LogLevel.Error);
throw new InternalError();
} catch (RemoteException e) {
writeLog(e, LogLevel.Error);
throw new InternalError();
}
return hash;
} catch (IOException e) {
writeLog(e, LogLevel.Error);
throw new InternalError();
} catch (SocketClosed e){
System.err.println("getHashSum512 : SocketClosed");
writeLog("getHashSum512 : SocketClosed", LogLevel.Error);
throw new InternalError();
}
}
/** Removes servers not owning the correct file to download from list.
* This is done by comparing hash512sum.
* @throws InternalError
*/
protected void purgeList() throws InternalError {
List<HostItem> blackList = new ArrayList<HostItem>();
boolean first = false;
byte[] hashsum;
for(HostItem host: hostList) {
// already have hashsum from 1st server
if (!first) {
first = true;
continue;
}
// ask hashsum
hashsum = getHashSum512(host);
if (!Arrays.equals(hash512, hashsum)) {
blackList.add(host);
}
}
// purge list
for(HostItem host: blackList) {
hostList.remove(host);
}
writeLog("Host list purge: done", LogLevel.Info);
}
/** Reassemble file from file parts.
* Set success to true if file is reassembled successfully.
*/
protected void reassembleFile() {
boolean firstPart = true;
boolean abort = false;
long nextOffset = 0;
do {
if (firstPart) {
writeLog("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);
nextOffset = (new File(dirStorage + filename)).length();
firstPart = false;
} catch (IOException e) {
writeLog("Reassembling: aborting on first part", LogLevel.Warning);
abort = true;
}
} else if (nextOffset >= size) {
success = true;
writeLog("Reassembling: success", LogLevel.Info);
} else {
// append to file
try {
Files.write(new File(dirStorage + filename).toPath(), Files.readAllBytes(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath()), StandardOpenOption.APPEND);
nextOffset = (new File(dirStorage + filename)).length();
} catch (IOException e) {
abort = true;
writeLog("Aborting: bad number " + nextOffset, LogLevel.Error);
}
}
} while((!success) && (!abort));
}
/** Set size of file to download. Also download first file part.
* @throws InternalError
*/
protected void setSize() throws InternalError {
ProtocolP2PPacket<?> d = createProtocolP2PPacket(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE));
try {
d.sendRequest(getHostItemSocket(hostList.get(0)));
try {
Payload p = d.receiveResponse().getPayload();
assert p instanceof FilePart : "This payload must be instance of FilePart";
if (!(p instanceof FilePart)) {
System.err.println("Error: cannot get size.");
writeLog("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() + "`");
writeLog("wrong file received: `" + fp.getFilename() + "`", LogLevel.Error);
throw new ProtocolError();
}
if (fp.getOffset() == 0) {
try {
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)");
writeLog("cannot write file (" + partsSubdir + filename + "_0.part)", LogLevel.Error);
}
size = fp.getTotalSize();
if (fp.getPartialContent().length == size) {
stop = true;
}
} else {
System.err.println("Error: wrong file part received.");
writeLog("wrong file part received.", LogLevel.Error);
throw new InternalError();
}
}
} catch (EmptyDirectory e) {
System.err.println("Error: empty directory.");
writeLog("empty directory.", LogLevel.Error);
throw new InternalError();
} catch (LocalException e) {
writeLog(e, LogLevel.Error);
throw new InternalError();
} catch (RemoteException e) {
writeLog(e, LogLevel.Error);
throw new InternalError();
}
} catch (IOException e) {
writeLog(e, LogLevel.Error);
throw new InternalError();
} catch (SocketClosed e){
System.err.println("setSize : SocketClosed");
writeLog("setSize : SocketClosed", LogLevel.Error);
}
}
/** Close HostItem socket
* @param hostItem HostItem
*/
protected abstract void closeHostItemSocket(HostItem hostItem);
/** Runnable implementation
*/
public void run() {
try {
init();
if (stop) {
writeLog("File is smaller than part max size.", LogLevel.Info);
closeHostItemSocket(hostList.get(0));
} else {
writeLog("File is bigger than part max size.", LogLevel.Info);
purgeList();
initThreads();
while(!stop) {
assignTasks();
checkTasksStatus();
}
}
writeLog("Reassembling file parts.", LogLevel.Info);
reassembleFile();
} catch(InternalError e) {
writeLog("Error while downloading file. Aborting.", LogLevel.Error);
} finally {
stopTasks();
}
}
/** Initialize infos about file to download (size, hash512sum, partslist to dl).
* Also download first partfile (to get size).
* @throws InternalError
*/
protected void init() throws InternalError {
// get size
setSize();
// get hashsum from 1st server in list
hash512 = getHashSum512(hostList.get(0));
if (hash512.length == 0) {
writeLog("no hash512sum support.", LogLevel.Error);
throw new InternalError();
}
// Add tasks
if (!stop) {
for(long i=MAX_PARTIAL_SIZE; i<size;i+=MAX_PARTIAL_SIZE) {
offsetsToAsk.add(Long.valueOf(i));
}
writeLog("Adding tasks: done", LogLevel.Info);
}
}
/** Getter for HostItem socket
* @param hostItem HostItem
*/
protected abstract Object getHostItemSocket(HostItem hostItem);
}

@ -0,0 +1,310 @@
package clientP2P;
import java.util.List;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.Payload;
import protocolP2P.LoadRequest;
import protocolP2P.FilePart;
import localException.InternalError;
import localException.ProtocolError;
import localException.TransmissionError;
import localException.VersionError;
import localException.SizeError;
import localException.SocketClosed;
import remoteException.EmptyDirectory;
import remoteException.EmptyFile;
import remoteException.InternalRemoteError;
import remoteException.VersionRemoteError;
import remoteException.ProtocolRemoteError;
import remoteException.NotFound;
import remoteException.NotATracker;
import exception.LocalException;
import exception.RemoteException;
import tools.Logger;
import tools.LogLevel;
import tools.ServeErrors;
/** Class to download file parts.
* @author Louis Royer
* @author Flavien Haas
* @author JS Auge
* @version 1.0
*/
public abstract class ClientDownloadPart extends ServeErrors implements Runnable {
protected List<Long> toDoTasks;
protected List<Long> pendingTasks;
protected List<Long> tasksDone;
protected volatile boolean tasksListsLock;
protected volatile boolean stop;
protected volatile boolean failed;
protected String filename;
protected volatile boolean noTask;
protected String partsSubdir;
protected static final long MAX_PARTIAL_SIZE = 4096;
protected ClientDownload manager;
protected Logger logger;
/** Constructor with filename, socket, and part subdir
* @param filename name of file to download
* @param socket socket to use
* @param partsSubdir directory to store .part files
* @param logger Logger
*/
public ClientDownloadPart(ClientDownload manager, String filename, String partsSubdir, Logger logger) {
this.manager = manager;
this.partsSubdir = partsSubdir;
this.filename = filename;
this.logger = logger;
stop = false;
failed = false;
pendingTasks = new ArrayList<>();
toDoTasks = new ArrayList<>();
tasksDone = new ArrayList<>();
noTask = true;
tasksListsLock = false;
}
/** True if thread has failed to get a file.
* @return true if thread has failed to get a file
*/
public boolean hasFailed() {
return failed;
}
/** Asks to stop thread.
* @throws InterruptedException
*/
public synchronized void setStop() throws InterruptedException {
stop = true;
this.notifyAll();
}
/** Runnable implementation */
public void run() {
while(!stop) {
try {
doTasks();
synchronized(manager) {
manager.notify();
}
} catch(InterruptedException e) {
try {
setStop();
synchronized(manager) {
manager.notify();
}
} catch (InterruptedException e2) {
}
}
}
writeLog("Closing socket", LogLevel.Info);
try{
closeSocket();
} catch(IOException e){
writeLog("can't close socket", LogLevel.Error);
}
}
/** Close the socket
*/
protected abstract void closeSocket() throws IOException;
/** Get list of offsets that have not be downloaded if failed, else
* empty list.
* @return list of offsets
*/
public List<Long> getFailed() {
List<Long> ret = new ArrayList<>();
if (failed) {
ret.addAll(pendingTasks);
ret.addAll(toDoTasks);
}
return ret;
}
/** Get list of downloaded file parts offset, then clear this list.
* @return list of offsets
* @throws InterruptedException
*/
public List<Long> getDone() throws InterruptedException {
if (tasksDone.size() == 0) {
return new ArrayList<>();
} else {
synchronized (this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
List<Long> ret = new ArrayList<>(tasksDone);
tasksDone.clear();
tasksListsLock = false;
this.notifyAll();
return ret;
}
}
}
/** Adds offset of files parts to download.
* @param task offset to download
* @throws InterruptedException
*/
public synchronized void assignTask(Long task) throws InterruptedException {
synchronized(this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
toDoTasks.add(task);
noTask = false;
tasksListsLock = false;
this.notifyAll();
}
}
/** Send one request and wait for one response. Blocks when no task.
* @throws InterruptedException
*/
public synchronized void doTasks() throws InterruptedException {
while(noTask && !stop) {
this.wait();
}
if (!stop) {
try {
Long offset = toDoTasks.get(0);
ProtocolP2PPacket<?> p = reqPart(offset);
if (p == null) {
stop = true;
}
failed = downloadPart(p);
if (failed) {
System.err.println("Error: DownloadPart failed.");
writeLog("DownloadPart failed.", LogLevel.Error);
stop = true;
} else if (toDoTasks.isEmpty()) {
noTask = true;
}
} catch (IndexOutOfBoundsException e) {
writeLog(e, LogLevel.Error);
noTask = true;
}
}
}
/** Send a request for a specific offset.
* @param offset Offset of the file part to download
* @return ProtocolP2PPacketTCP used to send request
*/
protected ProtocolP2PPacket<?> reqPart(Long offset) {
writeLog("New request: " + offset, LogLevel.Info);
// maintain tracking of tasks
if (toDoTasks.contains(offset)) {
try {
synchronized (this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
toDoTasks.remove(offset);
pendingTasks.add(offset);
tasksListsLock = false;
this.notifyAll();
}
} catch(InterruptedException e) {
writeLog("reqPart interruptedException", LogLevel.Error);
return null;
}
} else {
writeLog("reqPart (offset " + offset + " not in toDoTasks)", LogLevel.Error);
return null;
}
// send request
try {
ProtocolP2PPacket<?> d = createProtocolP2PPacket(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE));
d.sendRequest(getSocket());
return d;
} catch (InternalError e) {
writeLog("reqPart internalError", LogLevel.Error);
return null;
} catch (IOException e) {
writeLog("reqPart ioexception", LogLevel.Error);
writeLog(e, LogLevel.Error);
return null;
} catch (SocketClosed e){
writeLog("reqPart SocketClosed", LogLevel.Error);
return null;
}
}
/** Get the socket */
protected abstract Object getSocket();
/** Download file part associated to the request send (d).
* @param d request packet
* @return true on failure, else false
*/
public < T extends ProtocolP2PPacket<?> > boolean downloadPart(T d) {
if (d == null) {
writeLog("downloadPart -> d is null.", LogLevel.Error);
return true;
}
try {
Payload p = d.receiveResponse().getPayload();
assert p instanceof FilePart : "This payload must be instance of FilePart";
if (!(p instanceof FilePart)) {
writeLog("cannot get size.", LogLevel.Error);
return true;
} else {
FilePart fp = (FilePart)p;
if (!fp.getFilename().equals(filename)) {
writeLog("wrong file received: `" + fp.getFilename() + "`", LogLevel.Error);
return true;
}
Long offset = Long.valueOf(fp.getOffset());
if (pendingTasks.contains(offset)) {
try {
Files.write(new File(partsSubdir + filename + "_" + offset + ".part").toPath(), fp.getPartialContent());
} catch (IOException e) {
writeLog("cannot write file (" + partsSubdir + filename + "_" + offset + ".part)", LogLevel.Error);
}
} else {
writeLog("wrong file part received.", LogLevel.Error);
return true;
}
try {
synchronized(this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
pendingTasks.remove(offset);
tasksDone.add(offset);
tasksListsLock = false;
this.notifyAll();
}
} catch(InterruptedException e) {
writeLog("DownloadPart Interrupted exception", LogLevel.Error);
return true;
}
}
} catch (LocalException e) {
writeLog(e, LogLevel.Error);
return true;
} catch (RemoteException e) {
writeLog(e, LogLevel.Error);
return true;
} catch (IOException e) {
System.err.println("Error: downloadPart ioexception");
writeLog("downloadPart ioexception", LogLevel.Error);
return true;
}
return false;
}
}

@ -6,6 +6,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import protocolP2P.ProtocolP2PPacketTCP;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.Payload;
import protocolP2P.LoadRequest;
import protocolP2P.FilePart;
@ -24,6 +25,7 @@ import remoteException.NotFound;
import remoteException.NotATracker;
import tools.Logger;
import tools.LogLevel;
import clientP2P.ClientDownloadPart;
/** Class to download file parts on tcp.
* @author Louis Royer
@ -31,332 +33,55 @@ import tools.LogLevel;
* @author JS Auge
* @version 1.0
*/
public class ClientDownloadPartTCP implements Runnable {
public class ClientDownloadPartTCP extends ClientDownloadPart {
private List<Long> toDoTasks;
private List<Long> pendingTasks;
private List<Long> tasksDone;
private volatile boolean tasksListsLock;
private volatile boolean stop;
private volatile boolean failed;
private String filename;
private Socket socket;
private volatile boolean noTask;
private String partsSubdir;
private static final long MAX_PARTIAL_SIZE = 4096;
private ClientDownloadTCP manager;
private Logger logger;
/** Constructor with filename, socket, and part subdir
* @param filename name of file to download
* @param socket socket to use
* @param partsSubdir directory to store .part files
* @param logger Logger
*/
public ClientDownloadPartTCP(ClientDownloadTCP manager, String filename, Socket socket, String partsSubdir, Logger logger) {
this.manager = manager;
this.partsSubdir = partsSubdir;
this.filename = filename;
public ClientDownloadPartTCP(ClientDownload manager, String filename, Socket socket, String partsSubdir, Logger logger) {
super(manager, filename, partsSubdir, logger);
this.socket = socket;
this.logger = logger;
stop = false;
failed = false;
pendingTasks = new ArrayList<>();
toDoTasks = new ArrayList<>();
tasksDone = new ArrayList<>();
noTask = true;
tasksListsLock = false;
}
/** True if thread has failed to get a file.
* @return true if thread has failed to get a file
*/
public boolean hasFailed() {
return failed;
}
/** Asks to stop thread.
* @throws InterruptedException
*/
public synchronized void setStop() throws InterruptedException {
stop = true;
this.notifyAll();
}
/** Runnable implementation */
public void run() {
while(!stop) {
try {
doTasks();
synchronized(manager) {
manager.notify();
}
} catch(InterruptedException e) {
try {
setStop();
synchronized(manager) {
manager.notify();
}
} catch (InterruptedException e2) {
}
}
}
System.err.println("Closing socket");
logger.writeTCP("Closing socket", LogLevel.Info);
try{
socket.close();
} catch(IOException e){
System.err.println("can't close socket");
logger.writeTCP("can't close socket", LogLevel.Error);
}
}
/** Get list of offsets that have not be downloaded if failed, else
* empty list.
* @return list of offsets
*/
public List<Long> getFailed() {
List<Long> ret = new ArrayList<>();
if (failed) {
ret.addAll(pendingTasks);
ret.addAll(toDoTasks);
}
return ret;
/** Get the socket */
protected Object getSocket() {
return (Object) socket;
}
/** Get list of downloaded file parts offset, then clear this list.
* @return list of offsets
* @throws InterruptedException
/** Close the socket
*/
public List<Long> getDone() throws InterruptedException {
if (tasksDone.size() == 0) {
return new ArrayList<>();
} else {
synchronized (this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
List<Long> ret = new ArrayList<>(tasksDone);
tasksDone.clear();
tasksListsLock = false;
this.notifyAll();
return ret;
}
}
protected void closeSocket() throws IOException {
socket.close();
}
/** Adds offset of files parts to download.
* @param task offset to download
* @throws InterruptedException
/** Implementation of writeLog
* @param text Text to log
* @param logLevel level of logging
*/
public synchronized void assignTask(Long task) throws InterruptedException {
synchronized(this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
toDoTasks.add(task);
noTask = false;
tasksListsLock = false;
this.notifyAll();
}
protected void writeLog(String text, LogLevel logLevel) {
logger.writeTCP(text, logLevel);
}
/** Send one request and wait for one response. Blocks when no task.
* @throws InterruptedException
/** Implementation of writeLog
* @param e exception to log
* @param logLevel level of logging
*/
public synchronized void doTasks() throws InterruptedException {
while(noTask && !stop) {
this.wait();
}
if (!stop) {
try {
Long offset = toDoTasks.get(0);
ProtocolP2PPacketTCP<LoadRequest> p = reqPart(offset);
if (p == null) {
stop = true;
}
failed = downloadPart(p);
if (failed) {
System.err.println("Error: DownloadPart failed.");
logger.writeTCP("DownloadPart failed.", LogLevel.Error);
stop = true;
} else if (toDoTasks.isEmpty()) {
noTask = true;
}
} catch (IndexOutOfBoundsException e) {
logger.writeTCP(e, LogLevel.Error);
noTask = true;
}
}
protected void writeLog(Exception e, LogLevel logLevel) {
logger.writeTCP(e, logLevel);
}
/** Send a request for a specific offset.
* @param offset Offset of the file part to download
* @return ProtocolP2PPacketTCP used to send request
*/
private ProtocolP2PPacketTCP<LoadRequest> reqPart(Long offset) {
System.err.println("New request: " + offset);
logger.writeTCP("New request: " + offset, LogLevel.Info);
// maintain tracking of tasks
if (toDoTasks.contains(offset)) {
try {
synchronized (this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
toDoTasks.remove(offset);
pendingTasks.add(offset);
tasksListsLock = false;
this.notifyAll();
}
} catch(InterruptedException e) {
System.err.println("Error: reqPart interruptedException");
logger.writeTCP("reqPart interruptedException", LogLevel.Error);
return null;
}
} else {
System.err.println("Error: reqPart (offset " + offset + " not in toDoTasks)");
logger.writeTCP("reqPart (offset " + offset + " not in toDoTasks)", LogLevel.Error);
return null;
}
// send request
try {
ProtocolP2PPacketTCP<LoadRequest> d = new ProtocolP2PPacketTCP<>(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE));
d.sendRequest((Object)socket);
return d;
} catch (InternalError e) {
System.err.println("Error: reqPart internalError");
logger.writeTCP("reqPart internalError", LogLevel.Error);
return null;
} catch (IOException e) {
e.printStackTrace();
System.err.println("Error: reqPart ioexception");
logger.writeTCP("reqPart ioexception", LogLevel.Error);
return null;
} catch (SocketClosed e){
System.err.println("Error: reqPart SocketClosed");
logger.writeTCP("reqPart SocketClosed", LogLevel.Error);
return null;
}
}
/** Download file part associated to the request send (d).
* @param d request packet
* @return true on failure, else false
/** Create packets
* @param payload Payload
*/
public boolean downloadPart(ProtocolP2PPacketTCP<LoadRequest> d) {
if (d == null) {
System.err.println("Error: downloadPart -> d is null.");
logger.writeTCP("downloadPart -> d is null.", LogLevel.Error);
return true;
}
try {
Payload p = d.receiveResponse().getPayload();
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);
return true;
} 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);
return true;
}
Long offset = Long.valueOf(fp.getOffset());
if (pendingTasks.contains(offset)) {
try {
Files.write(new File(partsSubdir + filename + "_" + offset + ".part").toPath(), fp.getPartialContent());
} catch (IOException e) {
System.err.println("Error: cannot write file (" + partsSubdir + filename + "_" + offset + ".part)");
logger.writeTCP("cannot write file (" + partsSubdir + filename + "_" + offset + ".part)", LogLevel.Error);
}
} else {
System.err.println("Error: wrong file part received.");
logger.writeTCP("wrong file part received.", LogLevel.Error);
return true;
}
try {
synchronized(this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
pendingTasks.remove(offset);
tasksDone.add(offset);
tasksListsLock = false;
this.notifyAll();
}
} catch(InterruptedException e) {
System.err.println("Error: DownloadPart Interrupted exception");
logger.writeTCP("DownloadPart Interrupted exception", LogLevel.Error);
return true;
}
}
} catch (EmptyDirectory e) {
System.err.println("Error: empty directory.");
logger.writeTCP("empty directory.", LogLevel.Error);
return true;
} catch (EmptyFile e) {
System.err.println("Error: downloadPart emptyFile");
logger.writeTCP("downloadPart emptyFile", LogLevel.Error);
// TODO: use more specific errors
return true;
} catch (ProtocolError e) {
System.err.println("Error: downloadPart protocolError");
logger.writeTCP("downloadPart protocolError", LogLevel.Error);
return true;
} catch (InternalRemoteError e) {
System.err.println("Error: downloadPart internalRemoteError");
logger.writeTCP("downloadPart internalRemoteError", LogLevel.Error);
return true;
} catch (VersionRemoteError e) {
System.err.println("Error: downloadPart versionRemoteError");
logger.writeTCP("downloadPart versionRemoteError", LogLevel.Error);
return true;
} catch (ProtocolRemoteError e) {
System.err.println("Error: downloadPart protocolRemoteError");
logger.writeTCP("downloadPart protocolRemoteError", LogLevel.Error);
return true;
} catch (TransmissionError e) {
System.err.println("Error: downloadPart transmissionError");
logger.writeTCP("downloadPart transmissionError", LogLevel.Error);
return true;
} catch (VersionError e) {
System.err.println("Error: downloadPart versionError");
logger.writeTCP("downloadPart versionError", LogLevel.Error);
return true;
} catch (SizeError e) {
System.err.println("Error: downloadPart sizeError");
logger.writeTCP("downloadPart sizeError", LogLevel.Error);
return true;
} catch (NotFound e) {
System.err.println("Error: downloadPart notFound");
logger.writeTCP("downloadPart notFound", LogLevel.Error);
return true;
} catch (IOException e) {
System.err.println("Error: downloadPart ioexception");
logger.writeTCP("downloadPart ioexception", LogLevel.Error);
return true;
} catch (InternalError e) {
System.err.println("Error: downloadPart internalError");
logger.writeTCP("downloadPart internalError", LogLevel.Error);
return true;
} catch (SocketClosed e){
System.err.println("Error: downloadPart SocketClosed");
logger.writeTCP("downloadPart SocketClosed", LogLevel.Error);
return true;
} catch (NotATracker e) {
System.err.println("Error: downloadPart notATracker");
logger.writeTCP("downloadPart notATracker", LogLevel.Error);
return true;
}
return false;
protected < T extends Payload > ProtocolP2PPacket<T> createProtocolP2PPacket(T payload) {
return (ProtocolP2PPacket<T>)new ProtocolP2PPacketTCP<T>(payload);
}
}

@ -3,6 +3,7 @@ import java.util.List;
import java.util.ArrayList;
import java.net.DatagramSocket;
import protocolP2P.ProtocolP2PPacketUDP;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.Payload;
import protocolP2P.LoadRequest;
import protocolP2P.FilePart;
@ -23,6 +24,7 @@ import java.io.File;
import java.io.IOException;
import tools.Logger;
import tools.LogLevel;
import clientP2P.ClientDownloadPart;
/** Class to download file parts on udp.
* @author Louis Royer
@ -30,318 +32,54 @@ import tools.LogLevel;
* @author JS Auge
* @version 1.0
*/
public class ClientDownloadPartUDP implements Runnable {
public class ClientDownloadPartUDP extends ClientDownloadPart {
private List<Long> toDoTasks;
private List<Long> pendingTasks;
private List<Long> tasksDone;
private volatile boolean tasksListsLock;
private volatile boolean stop;
private volatile boolean failed;
private String filename;
private DatagramSocket socket;
private volatile boolean noTask;
private String partsSubdir;
private static final long MAX_PARTIAL_SIZE = 4096;
private ClientDownloadUDP manager;
private Logger logger;
/** Constructor with filename, socket, and part subdir
* @param filename name of file to download
* @param socket socket to use
* @param partsSubdir directory to store .part files
* @param logger Logger
*/
public ClientDownloadPartUDP(ClientDownloadUDP manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger) {
this.manager = manager;
this.partsSubdir = partsSubdir;
this.filename = filename;
public ClientDownloadPartUDP(ClientDownload manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger) {
super(manager, filename, partsSubdir, logger);
this.socket = socket;
this.logger = logger;
stop = false;
failed = false;
pendingTasks = new ArrayList<>();
toDoTasks = new ArrayList<>();
tasksDone = new ArrayList<>();
noTask = true;
tasksListsLock = false;
}
/** True if thread has failed to get a file.
* @return true if thread has failed to get a file
*/
public boolean hasFailed() {
return failed;
/** Get the socket */
protected Object getSocket() {
return (Object) socket;
}
/** Asks to stop thread.
* @throws InterruptedException
/** Close the socket
*/
public synchronized void setStop() throws InterruptedException {
stop = true;
this.notifyAll();
}
/** Runnable implementation */
public void run() {
while(!stop) {
try {
doTasks();
synchronized(manager) {
manager.notify();
}
} catch(InterruptedException e) {
try {
setStop();
synchronized(manager) {
manager.notify();
}
} catch (InterruptedException e2) {
}
}
}
System.err.println("Closing socket");
logger.writeUDP("Closing socket", LogLevel.Info);
protected void closeSocket() throws IOException {
socket.close();
}
/** Get list of offsets that have not be downloaded if failed, else
* empty list.
* @return list of offsets
*/
public List<Long> getFailed() {
List<Long> ret = new ArrayList<>();
if (failed) {
ret.addAll(pendingTasks);
ret.addAll(toDoTasks);
}
return ret;
}
/** Get list of downloaded file parts offset, then clear this list.
* @return list of offsets
* @throws InterruptedException
*/
public List<Long> getDone() throws InterruptedException {
if (tasksDone.size() == 0) {
return new ArrayList<>();
} else {
synchronized (this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
List<Long> ret = new ArrayList<>(tasksDone);
tasksDone.clear();
tasksListsLock = false;
this.notifyAll();
return ret;
}
}
}
/** Adds offset of files parts to download.
* @param task offset to download
* @throws InterruptedException
*/
public synchronized void assignTask(Long task) throws InterruptedException {
synchronized(this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
toDoTasks.add(task);
noTask = false;
tasksListsLock = false;
this.notifyAll();
}
}
/** Send one request and wait for one response. Blocks when no task.
* @throws InterruptedException
/** Implementation of writeLog
* @param text Text to log
* @param logLevel level of logging
*/
public synchronized void doTasks() throws InterruptedException {
while(noTask && !stop) {
this.wait();
}
if (!stop) {
try {
Long offset = toDoTasks.get(0);
ProtocolP2PPacketUDP<LoadRequest> p = reqPart(offset);
if (p == null) {
stop = true;
}
failed = downloadPart(p);
if (failed) {
System.err.println("Error: DownloadPart failed.");
stop = true;
} else if (toDoTasks.isEmpty()) {
noTask = true;
}
} catch (IndexOutOfBoundsException e) {
logger.writeUDP(e, LogLevel.Error);
noTask = true;
}
}
protected void writeLog(String text, LogLevel logLevel) {
logger.writeUDP(text, logLevel);
}
/** Send a request for a specific offset.
* @param offset Offset of the file part to download
* @return ProtocolP2PPacketTCP used to send request
/** Implementation of writeLog
* @param e exception to log
* @param logLevel level of logging
*/
private ProtocolP2PPacketUDP<LoadRequest> reqPart(Long offset) {
System.err.println("New request: "+ offset);
logger.writeUDP("New request: "+ offset, LogLevel.Info);
// maintain tracking of tasks
if (toDoTasks.contains(offset)) {
try {
synchronized (this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
toDoTasks.remove(offset);
pendingTasks.add(offset);
tasksListsLock = false;
this.notifyAll();
}
} catch(InterruptedException e) {
System.err.println("Error: reqPart interruptedException");
logger.writeUDP("reqPart interruptedException", LogLevel.Error);
return null;
}
} else {
System.err.println("Error: reqPart (offset " + offset + " not in toDoTasks)");
logger.writeUDP("reqPart (offset " + offset + " not in toDoTasks)", LogLevel.Error);
return null;
}
// send request
try {
ProtocolP2PPacketUDP<LoadRequest> d = new ProtocolP2PPacketUDP<>(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE));
d.sendRequest((Object)socket);
return d;
} catch (InternalError e) {
System.err.println("Error: reqPart internalError");
logger.writeUDP("reqPart internalError", LogLevel.Error);
return null;
} catch (IOException e) {
e.printStackTrace();
System.err.println("Error: reqPart ioexception");
logger.writeUDP("reqPart ioexception", LogLevel.Error);
return null;
}
protected void writeLog(Exception e, LogLevel logLevel) {
logger.writeUDP(e, logLevel);
}
/** Download file part associated to the request send (d).
* @param d request packet
* @return true on failure, else false
/** Create packets
* @param payload Payload
*/
public boolean downloadPart(ProtocolP2PPacketUDP<LoadRequest> d) {
if (d == null) {
System.err.println("Error: downloadPart -> d is null.");
logger.writeUDP("downloadPart -> d is null.", LogLevel.Error);
return true;
}
try {
Payload p = d.receiveResponse().getPayload();
assert p instanceof FilePart : "This payload must be instance of FilePart";
if (!(p instanceof FilePart)) {
System.err.println("Error: cannot get size.");
logger.writeUDP("cannot get size.", LogLevel.Error);
return true;
} else {
FilePart fp = (FilePart)p;
if (!fp.getFilename().equals(filename)) {
System.err.println("Error: wrong file received: `" + fp.getFilename() + "`");
logger.writeUDP("wrong file received: `" + fp.getFilename() + "`", LogLevel.Error);
return true;
}
Long offset = Long.valueOf(fp.getOffset());
if (pendingTasks.contains(offset)) {
try {
Files.write(new File(partsSubdir + filename + "_" + offset + ".part").toPath(), fp.getPartialContent());
} catch (IOException e) {
System.err.println("Error: cannot write file (" + partsSubdir + filename + "_" + offset + ".part)");
logger.writeUDP("cannot write file (" + partsSubdir + filename + "_" + offset + ".part)", LogLevel.Error);
}
} else {
System.err.println("Error: wrong file part received.");
logger.writeUDP("wrong file part received.", LogLevel.Error);
return true;
}
try {
synchronized(this) {
while(tasksListsLock) {
this.wait();
}
tasksListsLock = true;
pendingTasks.remove(offset);
tasksDone.add(offset);
tasksListsLock = false;
this.notifyAll();
}
} catch(InterruptedException e) {
System.err.println("Error: DownloadPart Interrupted exception");
logger.writeUDP("DownloadPart Interrupted exception", LogLevel.Error);
return true;
}
}
} catch (EmptyDirectory e) {
System.err.println("Error: empty directory.");
logger.writeUDP("empty directory.", LogLevel.Error);
return true;
} catch (EmptyFile e) {
System.err.println("Error: downloadPart emptyFile");
logger.writeUDP("downloadPart emptyFile", LogLevel.Error);
// TODO: use more specific errors
return true;
} catch (ProtocolError e) {
System.err.println("Error: downloadPart protocolError");
logger.writeUDP("downloadPart protocolError", LogLevel.Error);
return true;
} catch (InternalRemoteError e) {
System.err.println("Error: downloadPart internalRemoteError");
logger.writeUDP("downloadPart internalRemoteError", LogLevel.Error);
return true;
} catch (VersionRemoteError e) {
System.err.println("Error: downloadPart versionRemoteError");
logger.writeUDP("downloadPart versionRemoteError", LogLevel.Error);
return true;
} catch (ProtocolRemoteError e) {
System.err.println("Error: downloadPart protocolRemoteError");
logger.writeUDP("downloadPart protocolRemoteError", LogLevel.Error);
return true;
} catch (TransmissionError e) {
System.err.println("Error: downloadPart transmissionError");
logger.writeUDP("downloadPart transmissionError", LogLevel.Error);
return true;
} catch (VersionError e) {
System.err.println("Error: downloadPart versionError");
logger.writeUDP("downloadPart versionError", LogLevel.Error);
return true;
} catch (SizeError e) {
System.err.println("Error: downloadPart sizeError");
logger.writeUDP("downloadPart sizeError", LogLevel.Error);
return true;
} catch (NotFound e) {
System.err.println("Error: downloadPart notFound");
logger.writeUDP("downloadPart notFound", LogLevel.Error);
return true;
} catch (IOException e) {
System.err.println("Error: downloadPart ioexception");
logger.writeUDP("downloadPart ioexception", LogLevel.Error);
return true;
} catch (InternalError e) {
System.err.println("Error: downloadPart internalError");
logger.writeUDP("downloadPart internalError", LogLevel.Error);
return true;
} catch (NotATracker e) {
System.err.println("Error: downloadPart notATracker");
logger.writeUDP("downloadPart notATracker", LogLevel.Error);
return true;
}
return false;
protected < T extends Payload > ProtocolP2PPacket<T> createProtocolP2PPacket(T payload) {
return (ProtocolP2PPacket<T>)new ProtocolP2PPacketUDP<T>(payload);
}
}

@ -26,10 +26,12 @@ import protocolP2P.HashAlgorithm;
import protocolP2P.HashResponse;
import protocolP2P.HashRequest;
import protocolP2P.ProtocolP2PPacketTCP;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.Payload;
import protocolP2P.FilePart;
import protocolP2P.LoadRequest;
import clientP2P.ClientDownloadPartTCP;
import clientP2P.ClientDownload;
import tools.HostItem;
import tools.Logger;
import tools.LogLevel;
@ -40,407 +42,61 @@ import tools.LogLevel;
* @author JS Auge
* @version 1.0
*/
public class ClientDownloadTCP implements Runnable {
private List<HostItem> hostList;
private String filename;
private byte[] hash512;
private List<ClientDownloadPartTCP> sockList = new ArrayList<ClientDownloadPartTCP>();
private List<Long> offsetsToAsk = new ArrayList<Long>();
private List<Long> offsetsPending = new ArrayList<Long>();
private boolean stop;
private long size;
private static final long MAX_PARTIAL_SIZE = 4096;
private String partsSubdir;
private String dirStorage;
private boolean success = false;
private Logger logger;
public class ClientDownloadTCP extends ClientDownload {
/** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage
* @param filename name of file to download
* @param hostList list of servers
* @param partsSubdir directory to store .part files
* @param dirStorage directory to write assembled file
* @param logger Logger
*/
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;
super(filename, hostList, partsSubdir, dirStorage, logger);
}
/** Asks thread to stop
/** Create a clientDownloadPart
* @param filename name of the file to download
* @param hostItem Hostitem of the server
*/
public void setStop() {
stop = true;
protected ClientDownloadPart createDownloadPart(String filename, HostItem hostItem) {
return (ClientDownloadPart)new ClientDownloadPartTCP((ClientDownload)this, filename, hostItem.getTCPSocket(), partsSubdir, logger);
}
/** Runnable implementation
/** Close HostItem socket
* @param hostItem HostItem
*/
public void run() {
try {
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) {
assignTasks();
checkTasksStatus();
}
}
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();
}
protected void closeHostItemSocket(HostItem hostItem) {
hostItem.closeTCPSocket();
}
/** Starts threads for each server in hostList.
/** Implementation of writeLog
* @param text Text to log
* @param logLevel level of logging
*/
private void initThreads() {
for(HostItem hostItem: hostList) {
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.
* @throws InternalError
*/
private void checkTasksStatus() throws InternalError {
try {
synchronized(this) {
this.wait();
List<ClientDownloadPartTCP> sockListCpy = new ArrayList<>(sockList);
for(ClientDownloadPartTCP c: sockListCpy) {
if (c.hasFailed() == true) {
sockList.remove(c);
offsetsPending.removeAll(c.getFailed());
offsetsToAsk.addAll(c.getFailed());
}
try {
offsetsPending.removeAll(c.getDone());
} catch (InterruptedException e) {
throw new InternalError();
}
}
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();
}
}
/** Assign tasks randomly to threads.
* @throws InternalError
*/
private void assignTasks() throws InternalError {
Random rand = new Random();
for(long offset : offsetsToAsk) {
try {
sockList.get(rand.nextInt(sockList.size())).assignTask(offset);
offsetsPending.add(offset);
System.err.println("Assigned task "+ offset);
} catch(InterruptedException e) {
logger.writeTCP(e, LogLevel.Error);
throw new InternalError();
}
}
offsetsToAsk.removeAll(offsetsPending);
}
/** Stop threads */
private void stopTasks() {
for(ClientDownloadPartTCP c : sockList) {
try {
c.setStop();
} catch (InterruptedException e) {
logger.writeTCP(e, LogLevel.Error);
}
}
}
/** Get hashsum from server.
* @param hostItem server to ask hash
* @return hash512sum
* @throws InternalError
*/
private byte[] getHashSum512(HostItem hostItem) throws InternalError {
byte[] hash;
HashAlgorithm[] hashesAlgo = new HashAlgorithm[1];
hashesAlgo[0] = HashAlgorithm.SHA512;
ProtocolP2PPacketTCP<HashRequest> d = new ProtocolP2PPacketTCP<>(new HashRequest(filename, hashesAlgo));
try {
d.sendRequest((Object)hostItem.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 {
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();
} catch (NotATracker 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();
}
}
/** Removes servers not owning the correct file to download from list.
* This is done by comparing hash512sum.
* @throws InternalError
*/
private void purgeList() throws InternalError {
List<HostItem> blackList = new ArrayList<HostItem>();
boolean first = false;
byte[] hashsum;
for(HostItem host: hostList) {
// already have hashsum from 1st server
if (!first) {
first = true;
continue;
}
// ask hashsum
hashsum = getHashSum512(host);
if (!Arrays.equals(hash512, hashsum)) {
blackList.add(host);
}
}
// purge list
for(HostItem host: blackList) {
hostList.remove(host);
}
System.err.println("Host list purge: done");
logger.writeTCP("Host list purge: done", LogLevel.Info);
}
/** Getter for hash512sum
* @return hash512sum
*/
public byte[] getHashSum512() {
return hash512;
}
/** Initialize infos about file to download (size, hash512sum, partslist to dl).
* Also download first partfile (to get size).
* @throws InternalError
*/
private void init() throws InternalError {
// get size
setSize();
// get hashsum from 1st server in list
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();
}
// Add tasks
if (!stop) {
for(long i=MAX_PARTIAL_SIZE; i<size;i+=MAX_PARTIAL_SIZE) {
offsetsToAsk.add(Long.valueOf(i));
}
System.err.println("Adding tasks: done");
logger.writeTCP("Adding tasks: done", LogLevel.Info);
}
protected void writeLog(String text, LogLevel logLevel) {
logger.writeTCP(text, logLevel);
}
/** Set size of file to download. Also download first file part.
* @throws InternalError
/** Implementation of writeLog
* @param e exception to log
* @param logLevel level of logging
*/
private void setSize() throws InternalError {
ProtocolP2PPacketTCP<LoadRequest> d = new ProtocolP2PPacketTCP<>(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE));
try {
d.sendRequest((Object)hostList.get(0).getTCPSocket());
try {
Payload p = d.receiveResponse().getPayload();
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) {
try {
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) {
stop = true;
}
} 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 (NotATracker 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);
}
protected void writeLog(Exception e, LogLevel logLevel) {
logger.writeTCP(e, logLevel);
}
/** Success getter.
* @return true when file have successfully been reassembled.
/** Create packets
* @param payload Payload
*/
public boolean getSuccess() {
return success;
protected < T extends Payload > ProtocolP2PPacket<T> createProtocolP2PPacket(T payload) {
return (ProtocolP2PPacket<T>)new ProtocolP2PPacketTCP<T>(payload);
}
/** Reassemble file from file parts.
* Set success to true if file is reassembled successfully.
/** Getter for HostItem socket
* @param hostItem HostItem
*/
private void reassembleFile() {
boolean firstPart = true;
boolean abort = false;
long nextOffset = 0;
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);
nextOffset = (new File(dirStorage + filename)).length();
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 {
Files.write(new File(dirStorage + filename).toPath(), Files.readAllBytes(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath()), StandardOpenOption.APPEND);
nextOffset = (new File(dirStorage + filename)).length();
} catch (IOException e) {
abort = true;
System.err.println("Aborting: bad number " + nextOffset);
logger.writeTCP("Aborting: bad number " + nextOffset, LogLevel.Error);
}
}
} while((!success) && (!abort));
protected Object getHostItemSocket(HostItem hostItem) {
return (Object)hostItem.getTCPSocket();
}
}

@ -25,10 +25,12 @@ import protocolP2P.HashAlgorithm;
import protocolP2P.HashResponse;
import protocolP2P.HashRequest;
import protocolP2P.ProtocolP2PPacketUDP;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.Payload;
import protocolP2P.FilePart;
import protocolP2P.LoadRequest;
import clientP2P.ClientDownloadPartUDP;
import clientP2P.ClientDownload;
import tools.HostItem;
import tools.Logger;
import tools.LogLevel;
@ -40,400 +42,61 @@ import tools.LogLevel;
* @author JS Auge
* @version 1.0
*/
public class ClientDownloadUDP implements Runnable {
private List<HostItem> hostList;
private String filename;
private byte[] hash512;
private List<ClientDownloadPartUDP> sockList = new ArrayList<ClientDownloadPartUDP>();
private List<Long> offsetsToAsk = new ArrayList<Long>();
private List<Long> offsetsPending = new ArrayList<Long>();
private boolean stop;
private long size;
private static final long MAX_PARTIAL_SIZE = 4096;
private String partsSubdir;
private String dirStorage;
private boolean success = false;
private Logger logger;
public class ClientDownloadUDP extends ClientDownload {
/** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage
* @param filename name of file to download
* @param hostList list of servers
* @param partsSubdir directory to store .part files
* @param dirStorage directory to write assembled file
* @param logger Logger
*/
public ClientDownloadUDP(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;
}
/** Asks thread to stop
*/
public void setStop() {
stop = true;
}
/** Runnable implementation
*/
public void run() {
try {
init();
if (stop) {
System.err.println("File is smaller than part max size.");
logger.writeUDP("File is smaller than part max size.", LogLevel.Info);
hostList.get(0).closeUDPSocket();
} else {
System.err.println("File is bigger than part max size.");
logger.writeUDP("File is bigger than part max size.", LogLevel.Info);
purgeList();
initThreads();
while(!stop) {
assignTasks();
checkTasksStatus();
}
}
System.err.println("Reassembling file parts.");
logger.writeUDP("Reassembling file parts.", LogLevel.Info);
reassembleFile();
} catch(InternalError e) {
System.err.println("Error while downloading file. Aborting.");
logger.writeUDP("Error while downloading file. Aborting.", LogLevel.Error);
} finally {
stopTasks();
}
}
/** Starts threads for each server in hostList.
*/
private void initThreads() {
for(HostItem hostItem: hostList) {
sockList.add(new ClientDownloadPartUDP(this, filename, hostItem.getUDPSocket(), partsSubdir, logger));
}
for(ClientDownloadPartUDP c: sockList) {
Thread t = new Thread(c);
t.start();
}
System.err.println("Threads initialized");
logger.writeUDP("Threads initialized", LogLevel.Error);
}
/** Remove tasks from failed threads. Update done status.
* @throws InternalError
*/
private void checkTasksStatus() throws InternalError {
try {
synchronized(this) {
this.wait();
List<ClientDownloadPartUDP> sockListCpy = new ArrayList<>(sockList);
for(ClientDownloadPartUDP c: sockListCpy) {
if (c.hasFailed() == true) {
sockList.remove(c);
offsetsPending.removeAll(c.getFailed());
offsetsToAsk.addAll(c.getFailed());
}
try {
offsetsPending.removeAll(c.getDone());
} catch (InterruptedException e) {
throw new InternalError();
}
}
System.err.println("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending");
logger.writeUDP("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.writeUDP("No thread working", LogLevel.Error);
throw new InternalError();
}
}
} catch (InterruptedException e) {
throw new InternalError();
}
}
/** Assign tasks randomly to threads.
* @throws InternalError
*/
private void assignTasks() throws InternalError {
Random rand = new Random();
for(long offset : offsetsToAsk) {
try {
sockList.get(rand.nextInt(sockList.size())).assignTask(offset);
offsetsPending.add(offset);
System.err.println("Assigned task "+ offset);
logger.writeUDP("Assigned task "+ offset, LogLevel.Info);
} catch(InterruptedException e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
}
}
offsetsToAsk.removeAll(offsetsPending);
}
/** Stop threads */
private void stopTasks() {
for(ClientDownloadPartUDP c : sockList) {
try {
c.setStop();
} catch (InterruptedException e) {
logger.writeUDP(e, LogLevel.Error);
}
}
}
/** Get hashsum from server.
* @param hostItem server to ask hash
* @return hash512sum
* @throws InternalError
*/
private byte[] getHashSum512(HostItem hostItem) throws InternalError {
byte[] hash;
HashAlgorithm[] hashesAlgo = new HashAlgorithm[1];
hashesAlgo[0] = HashAlgorithm.SHA512;
ProtocolP2PPacketUDP<HashRequest> d = new ProtocolP2PPacketUDP<>(new HashRequest(filename, hashesAlgo));
try {
d.sendRequest((Object)hostItem.getUDPSocket());
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 {
hash = ((HashResponse)pHash).getHash(HashAlgorithm.SHA512);
}
} catch (EmptyDirectory e) {
logger.writeUDP(e, LogLevel.Error);
hash = new byte[0];
} catch (NotFound e) {
logger.writeUDP(e, LogLevel.Error);
hash = new byte[0];
// TODO: use more specific errors
} catch (EmptyFile e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (ProtocolError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (InternalRemoteError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (VersionRemoteError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (ProtocolRemoteError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (TransmissionError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (VersionError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (SizeError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (NotATracker e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
}
return hash;
} catch (IOException e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
}
super(filename, hostList, partsSubdir, dirStorage, logger);
}
/** Removes servers not owning the correct file to download from list.
* This is done by comparing hash512sum.
* @throws InternalError
/** Create a clientDownloadPart
* @param filename name of the file to download
* @param hostItem Hostitem of the server
*/
private void purgeList() throws InternalError {
List<HostItem> blackList = new ArrayList<HostItem>();
boolean first = false;
byte[] hashsum;
for(HostItem host: hostList) {
// already have hashsum from 1st server
if (!first) {
first = true;
continue;
}
// ask hashsum
hashsum = getHashSum512(host);
if (!Arrays.equals(hash512, hashsum)) {
blackList.add(host);
}
}
// purge list
for(HostItem host: blackList) {
hostList.remove(host);
}
System.err.println("Host list purge: done");
logger.writeUDP("Host list purge: done", LogLevel.Info);
protected ClientDownloadPart createDownloadPart(String filename, HostItem hostItem) {
return (ClientDownloadPart)new ClientDownloadPartUDP((ClientDownload)this, filename, hostItem.getUDPSocket(), partsSubdir, logger);
}
/** Getter for hash512sum
* @return hash512sum
/** Implementation of writeLog
* @param text Text to log
* @param logLevel level of logging
*/
public byte[] getHashSum512() {
return hash512;
protected void writeLog(String text, LogLevel logLevel) {
logger.writeUDP(text, logLevel);
}
/** Initialize infos about file to download (size, hash512sum, partslist to dl).
* Also download first partfile (to get size).
* @throws InternalError
/** Implementation of writeLog
* @param e exception to log
* @param logLevel level of logging
*/
private void init() throws InternalError {
// get size
setSize();
// get hashsum from 1st server in list
hash512 = getHashSum512(hostList.get(0));
if (hash512.length == 0) {
System.err.println("Error: no hash512sum support.");
logger.writeUDP("no hash512sum support.", LogLevel.Error);
throw new InternalError();
}
// Add tasks
if (!stop) {
for(long i=MAX_PARTIAL_SIZE; i<size;i+=MAX_PARTIAL_SIZE) {
offsetsToAsk.add(Long.valueOf(i));
}
System.err.println("Adding tasks: done");
logger.writeUDP("Adding tasks: done", LogLevel.Info);
}
protected void writeLog(Exception e, LogLevel logLevel) {
logger.writeUDP(e, logLevel);
}
/** Set size of file to download. Also download first file part.
* @throws InternalError
/** Create packets
* @param payload Payload
*/
private void setSize() throws InternalError {
ProtocolP2PPacketUDP<LoadRequest> d = new ProtocolP2PPacketUDP<>(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE));
try {
d.sendRequest((Object)hostList.get(0).getUDPSocket());
try {
Payload p = d.receiveResponse().getPayload();
assert p instanceof FilePart : "This payload must be instance of FilePart";
if (!(p instanceof FilePart)) {
System.err.println("Error: cannot get size.");
logger.writeUDP("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.writeUDP("wrong file received: `" + fp.getFilename() + "`", LogLevel.Error);
throw new ProtocolError();
}
if (fp.getOffset() == 0) {
try {
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.writeUDP("cannot write file (" + partsSubdir + filename + "_0.part)", LogLevel.Error);
}
size = fp.getTotalSize();
if (fp.getPartialContent().length == size) {
stop = true;
}
} else {
System.err.println("Error: wrong file part received.");
logger.writeUDP("wrong file part received.", LogLevel.Error);
throw new InternalError();
}
}
} catch (EmptyDirectory e) {
System.err.println("Error: empty directory.");
logger.writeUDP("empty directory.", LogLevel.Error);
throw new InternalError();
} catch (EmptyFile e) {
logger.writeUDP(e, LogLevel.Error);
// TODO: use more specific errors
throw new InternalError();
} catch (ProtocolError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (InternalRemoteError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (VersionRemoteError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (ProtocolRemoteError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (TransmissionError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (VersionError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (SizeError e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (NotFound e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
} catch (NotATracker e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
}
} catch (IOException e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
}
protected < T extends Payload > ProtocolP2PPacket<T> createProtocolP2PPacket(T payload) {
return (ProtocolP2PPacket<T>)new ProtocolP2PPacketUDP<T>(payload);
}
/** Success getter.
* @return true when file have successfully been reassembled.
/** Getter for HostItem socket
* @param hostItem HostItem
*/
public boolean getSuccess() {
return success;
protected Object getHostItemSocket(HostItem hostItem) {
return (Object)hostItem.getUDPSocket();
}
/** Reassemble file from file parts.
* Set success to true if file is reassembled successfully.
/** Close HostItem socket
* @param hostItem HostItem
*/
private void reassembleFile() {
boolean firstPart = true;
boolean abort = false;
long nextOffset = 0;
do {
if (firstPart) {
System.err.println("Reassembling: First part");
logger.writeUDP("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);
nextOffset = (new File(dirStorage + filename)).length();
firstPart = false;
} catch (IOException e) {
System.err.println("Reassembling: aborting on first part");
logger.writeUDP("Reassembling: aborting on first part", LogLevel.Warning);
abort = true;
}
} else if (nextOffset >= size) {
success = true;
System.err.println("Reassembling: success");
logger.writeUDP("Reassembling: success", LogLevel.Info);
} else {
// append to file
try {
Files.write(new File(dirStorage + filename).toPath(), Files.readAllBytes(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath()), StandardOpenOption.APPEND);
nextOffset = (new File(dirStorage + filename)).length();
} catch (IOException e) {
abort = true;
System.err.println("Aborting: bad number " + nextOffset);
logger.writeUDP("Aborting: bad number " + nextOffset, LogLevel.Error);
}
}
} while((!success) && (!abort));
protected void closeHostItemSocket(HostItem hostItem) {
hostItem.closeUDPSocket();
}
}

@ -0,0 +1,262 @@
package clientP2P;
import tools.HostItem;
import tools.Logger;
import tools.LogLevel;
import java.util.Scanner;
import java.util.List;
import localException.ProtocolError;
import tools.ServeErrors;
import protocolP2P.RequestResponseCode;
import protocolP2P.FileList;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.DiscoverRequest;
import protocolP2P.DiscoverResponse;
import protocolP2P.Payload;
import protocolP2P.HashAlgorithm;
import localException.InternalError;
import localException.ProtocolError;
import localException.SizeError;
import localException.TransmissionError;
import localException.VersionError;
import localException.SocketClosed;
import remoteException.EmptyFile;
import remoteException.EmptyDirectory;
import remoteException.InternalRemoteError;
import remoteException.NotFound;
import remoteException.ProtocolRemoteError;
import remoteException.VersionRemoteError;
import remoteException.NotATracker;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
/** Implementation of P2P-JAVA-PROJECT CLIENT
* @author Louis Royer
* @author Flavien Haas
* @author JS Auge
* @version 1.0
*/
public abstract class ClientManagement extends ServeErrors implements Runnable {
protected String baseDirectory;
protected String partsSubdir;
protected List<HostItem> hostList;
protected HostItem tracker;
protected Logger logger;
protected Scanner scanner;
protected ClientDownload downLoader;
/** Constructor with baseDirectory, tracker, partsSubdir, logger, and scanner parameters.
* @param baseDirectory the root directory where files are stored
* @param tracker Tracker hostItem
* @param partsSubdir subdirectory to store file parts
* @param logger Loggger
* @param scanner Scanner used to read input
*/
public ClientManagement(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) {
this.scanner = scanner;
this.baseDirectory = baseDirectory;
this.tracker = tracker;
this.partsSubdir = partsSubdir;
this.logger = logger;
try {
initHostList();
} catch (InternalError e) {
System.exit(-1);
} catch (ProtocolError e) {
System.exit(-2);
}
}
/** Getter for tracker socket
*/
protected abstract Object getTrackerSocket();
/** Initialize hostList from tracker
* @throws ProtocolError
* @throws InternalError
*/
private void initHostList() throws ProtocolError, InternalError {
ProtocolP2PPacket<?> d = createProtocolP2PPacket(new DiscoverRequest(null));
try {
d.sendRequest(getTrackerSocket());
Payload p = d.receiveResponse().getPayload();
assert p instanceof DiscoverResponse : "This payload must be instance of Filelist";
if (!(p instanceof DiscoverResponse)) {
throw new InternalError();
} else {
hostList = ((DiscoverResponse)p).getHostList();
}
} catch (SocketClosed e){
writeLog("listDirectory : SocketClosed", LogLevel.Error);
throw new ProtocolError();
} catch (NotATracker e) {
writeLog(e, LogLevel.Error);
throw new ProtocolError();
} catch (Exception e) {
writeLog(e, LogLevel.Error);
throw new ProtocolError();
}
}
/** Compute Hashsum of a file.
* @param filename
* @return hashsum
*/
protected 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) {
writeLog(h.getName() + " not supported", LogLevel.Error);
} catch (IOException e) {
writeLog("cannot read " + filename, LogLevel.Error);
}
return new byte[0];
}
/** Getter for HostItem socket
* @param hostItem HostItem
*/
protected abstract Object getHostItemSocket(HostItem hostItem);
/** 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
*/
protected String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
ProtocolP2PPacket<?> d = createProtocolP2PPacket(new Payload(RequestResponseCode.LIST_REQUEST));
try {
d.sendRequest(getHostItemSocket(hostList.get(0)));
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) {
writeLog(e, LogLevel.Error);
throw new ProtocolError();
} catch (EmptyFile e) {
writeLog(e, LogLevel.Error);
throw new ProtocolError();
} catch (SocketClosed e){
writeLog("listDirectory : SocketClosed", LogLevel.Error);
throw new ProtocolError();
} catch (NotATracker e) {
writeLog(e, LogLevel.Error);
throw new ProtocolError();
}
}
/** Initialize downloader
* @param filename Name of the file to download
*/
protected abstract void initDownloader(String filename);
/** 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 {
initDownloader(filename);
Thread t = new Thread(downLoader);
t.start();
try {
t.join();
if (downLoader.getSuccess()) {
byte[] hash512 = downLoader.getHashSum512();
if (!Arrays.equals(hash512, computeHashsum(filename, HashAlgorithm.SHA512))) {
writeLog("Hashsum does not match", LogLevel.Error);
String line = "Computed checksum:\n";
byte[] c = computeHashsum(filename, HashAlgorithm.SHA512);
for (byte b: c) {
line += String.format("%02X", b);
}
line += "\nReceived checksum:\n";
for (byte b: hash512) {
line += String.format("%02X", b);
}
line += "\n";
writeLog(line, LogLevel.Info);
throw new InternalError();
}
} else {
throw new InternalError();
}
} catch (InterruptedException e) {
throw new InternalError();
}
}
/** 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:");
String f = scanner.nextLine();
download(f);
System.out.println("File " + f + " sucessfully downloaded");
writeLog("File " + f + " sucessfully downloaded", LogLevel.Info);
} catch (EmptyDirectory e) {
writeLog("Server has no file in directory", LogLevel.Error);
} catch (InternalError e) {
writeLog("Client internal error", LogLevel.Error);
} catch (UnknownHostException e) {
writeLog("Server host is unknown", LogLevel.Error);
} catch (IOException e) {
writeLog("Request cannot be send or response cannot be received", LogLevel.Error);
} catch (TransmissionError e) {
writeLog("Message received is too big", LogLevel.Error);
} catch (ProtocolError e) {
writeLog("Cannot decode servers response", LogLevel.Error);
} catch (VersionError e) {
writeLog("Servers response use bad version of the protocol", LogLevel.Error);
} catch (SizeError e) {
writeLog("Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error);
} catch (InternalRemoteError e) {
writeLog("Server internal error", LogLevel.Error);
} catch (ProtocolRemoteError e) {
writeLog("Server cannot decode clients request", LogLevel.Error);
} catch (VersionRemoteError e) {
writeLog("Server cannot decode this version of the protocol", LogLevel.Error);
} catch (NotFound e) {
writeLog("Server has not this file in directory", LogLevel.Error);
} catch (EmptyFile e) {
writeLog("File is empty", LogLevel.Error);
}
}
}

@ -1,38 +1,15 @@
package clientP2P;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import localException.InternalError;
import localException.ProtocolError;
import localException.SizeError;
import localException.TransmissionError;
import localException.VersionError;
import localException.SocketClosed;
import remoteException.EmptyFile;
import remoteException.EmptyDirectory;
import remoteException.InternalRemoteError;
import remoteException.NotFound;
import remoteException.ProtocolRemoteError;
import remoteException.VersionRemoteError;
import remoteException.NotATracker;
import protocolP2P.ProtocolP2PPacketTCP;
import protocolP2P.Payload;
import protocolP2P.RequestResponseCode;
import protocolP2P.FileList;
import protocolP2P.HashAlgorithm;
import clientP2P.ClientDownloadTCP;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.ProtocolP2PPacketTCP;
import tools.HostItem;
import tools.Logger;
import tools.LogLevel;
import protocolP2P.DiscoverRequest;
import protocolP2P.DiscoverResponse;
import clientP2P.ClientDownloadTCP;
import clientP2P.ClientManagement;
/** Implementation of P2P-JAVA-PROJECT CLIENT
* @author Louis Royer
@ -40,14 +17,7 @@ import protocolP2P.DiscoverResponse;
* @author JS Auge
* @version 1.0
*/
public class ClientManagementTCP implements Runnable {
private String baseDirectory;
private String partsSubdir;
private List<HostItem> hostList;
private HostItem tracker;
private Logger logger;
private Scanner scanner;
public class ClientManagementTCP extends ClientManagement {
/** Constructor for TCP implementation, with baseDirectory, tracker, partsSubdir, logger, and scanner parameters.
* @param baseDirectory the root directory where files are stored
* @param tracker Tracker hostItem
@ -56,189 +26,51 @@ public class ClientManagementTCP implements Runnable {
* @param scanner Scanner used to read input
*/
public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) {
this.scanner = scanner;
this.baseDirectory = baseDirectory;
this.tracker = tracker;
this.partsSubdir = partsSubdir;
this.logger = logger;
try {
initHostList();
} catch (InternalError e) {
System.exit(-1);
} catch (ProtocolError e) {
System.exit(-2);
}
super(baseDirectory, tracker, partsSubdir, logger, scanner);
}
/** Implementation of Runnable
/** Initialize downloader
* @param filename Name of the file to download
*/
protected void initDownloader(String filename) {
downLoader = (ClientDownload) new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger);
}
/** Implementation of writeLog
* @param text Text to log
* @param logLevel level of logging
*/
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:");
String f = scanner.nextLine();
download(f);
System.out.println("File " + f + " sucessfully downloaded");
logger.writeTCP("File " + f + " sucessfully downloaded", LogLevel.Info);
} catch (EmptyDirectory e) {
logger.writeTCP("Server has no file in directory", LogLevel.Error);
} catch (InternalError e) {
logger.writeTCP("Client internal error", LogLevel.Error);
} catch (UnknownHostException e) {
logger.writeTCP("Server host is unknown", LogLevel.Error);
} catch (IOException e) {
logger.writeTCP("Request cannot be send or response cannot be received", LogLevel.Error);
} catch (TransmissionError e) {
logger.writeTCP("Message received is too big", LogLevel.Error);
} catch (ProtocolError e) {
logger.writeTCP("Cannot decode servers response", LogLevel.Error);
} catch (VersionError e) {
logger.writeTCP("Servers response use bad version of the protocol", LogLevel.Error);
} catch (SizeError e) {
logger.writeTCP("Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error);
} catch (InternalRemoteError e) {
logger.writeTCP("Server internal error", LogLevel.Error);
} catch (ProtocolRemoteError e) {
logger.writeTCP("Server cannot decode clients request", LogLevel.Error);
} catch (VersionRemoteError e) {
logger.writeTCP("Server cannot decode this version of the protocol", LogLevel.Error);
} catch (NotFound e) {
logger.writeTCP("Server has not this file in directory", LogLevel.Error);
} catch (EmptyFile e) {
logger.writeTCP("File is empty", LogLevel.Error);
}
protected void writeLog(String text, LogLevel logLevel) {
logger.writeTCP(text, logLevel);
}
/** 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
/** Implementation of writeLog
* @param e exception to log
* @param logLevel level of logging
*/
private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
ClientDownloadTCP downLoader = new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger);
Thread t = new Thread(downLoader);
t.start();
try {
t.join();
if (downLoader.getSuccess()) {
byte[] hash512 = downLoader.getHashSum512();
if (!Arrays.equals(hash512, computeHashsum(filename, HashAlgorithm.SHA512))) {
logger.writeTCP("Hashsum does not match", LogLevel.Error);
String line = "Computed checksum:\n";
byte[] c = computeHashsum(filename, HashAlgorithm.SHA512);
for (byte b: c) {
line += String.format("%02X", b);
}
line += "\nReceived checksum:\n";
for (byte b: hash512) {
line += String.format("%02X", b);
}
line += "\n";
logger.writeTCP(line, LogLevel.Info);
throw new InternalError();
}
} else {
throw new InternalError();
}
} catch (InterruptedException e) {
throw new InternalError();
}
protected void writeLog(Exception e, LogLevel logLevel) {
logger.writeTCP(e, logLevel);
}
/** 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
/** Create packets
* @param payload Payload
*/
private String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
ProtocolP2PPacketTCP<Payload> d = new ProtocolP2PPacketTCP<>(new Payload(RequestResponseCode.LIST_REQUEST));
try {
d.sendRequest((Object)hostList.get(0).getTCPSocket());
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) {
logger.writeTCP(e, LogLevel.Error);
throw new ProtocolError();
} catch (EmptyFile e) {
logger.writeTCP(e, LogLevel.Error);
throw new ProtocolError();
} catch (SocketClosed e){
logger.writeTCP("listDirectory : SocketClosed", LogLevel.Error);
throw new ProtocolError();
} catch (NotATracker e) {
logger.writeTCP(e, LogLevel.Error);
throw new ProtocolError();
}
protected < T extends Payload > ProtocolP2PPacket<T> createProtocolP2PPacket(T payload) {
return (ProtocolP2PPacket<T>)new ProtocolP2PPacketTCP<T>(payload);
}
/** Compute Hashsum of a file.
* @param filename
* @return hashsum
/** Getter for tracker socket
*/
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) {
logger.writeTCP(h.getName() + " not supported", LogLevel.Error);
} catch (IOException e) {
logger.writeTCP("cannot read " + filename, LogLevel.Error);
}
return new byte[0];
protected Object getTrackerSocket() {
return (Object)tracker.getTCPSocket();
}
/** Initialize hostList from tracker
* @throws ProtocolError
* @throws InternalError
/** Getter for HostItem socket
* @param hostItem HostItem
*/
private void initHostList() throws ProtocolError, InternalError {
ProtocolP2PPacketTCP<DiscoverRequest> d = new ProtocolP2PPacketTCP<>(new DiscoverRequest(null));
try {
d.sendRequest((Object)tracker.getTCPSocket());
Payload p = d.receiveResponse().getPayload();
assert p instanceof DiscoverResponse : "This payload must be instance of Filelist";
if (!(p instanceof DiscoverResponse)) {
throw new InternalError();
} else {
hostList = ((DiscoverResponse)p).getHostList();
}
} catch (SocketClosed e){
logger.writeTCP("listDirectory : SocketClosed", LogLevel.Error);
throw new ProtocolError();
} catch (NotATracker e) {
logger.writeTCP(e, LogLevel.Error);
throw new ProtocolError();
} catch (Exception e) {
logger.writeTCP(e, LogLevel.Error);
throw new ProtocolError();
}
protected Object getHostItemSocket(HostItem hostItem) {
return (Object)hostItem.getTCPSocket();
}
}

@ -1,37 +1,14 @@
package clientP2P;
import java.util.Scanner;
import java.util.Arrays;
import java.util.List;
import java.io.IOException;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import localException.InternalError;
import localException.ProtocolError;
import localException.SizeError;
import localException.TransmissionError;
import localException.VersionError;
import remoteException.EmptyFile;
import remoteException.EmptyDirectory;
import remoteException.InternalRemoteError;
import remoteException.NotFound;
import remoteException.ProtocolRemoteError;
import remoteException.VersionRemoteError;
import remoteException.NotATracker;
import protocolP2P.ProtocolP2PPacketUDP;
import protocolP2P.Payload;
import protocolP2P.RequestResponseCode;
import protocolP2P.FileList;
import protocolP2P.HashAlgorithm;
import protocolP2P.DiscoverRequest;
import protocolP2P.DiscoverResponse;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.ProtocolP2PPacketUDP;
import tools.HostItem;
import tools.Logger;
import tools.LogLevel;
import clientP2P.ClientDownloadUDP;
import clientP2P.ClientManagement;
/** Implementation of P2P-JAVA-PROJECT CLIENT
* @author Louis Royer
@ -39,14 +16,7 @@ import clientP2P.ClientDownloadUDP;
* @author JS Auge
* @version 1.0
*/
public class ClientManagementUDP implements Runnable {
private String baseDirectory;
private String partsSubdir;
private List<HostItem> hostList;
private HostItem tracker;
private Logger logger;
private Scanner scanner;
public class ClientManagementUDP extends ClientManagement {
/** Constructor for UDP implementation, with baseDirectory, tracker, partsSubdir, logger and scanner parameters.
* @param baseDirectory the root directory where files are stored
* @param tracker tracker HostItem
@ -55,201 +25,56 @@ public class ClientManagementUDP implements Runnable {
* @param scanner Scanner used to read input
*/
public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) {
this.scanner = scanner;
this.baseDirectory = baseDirectory;
this.tracker = tracker;
this.partsSubdir = partsSubdir;
this.logger = logger;
try {
initHostList();
} catch (InternalError e) {
System.exit(-1);
} catch (ProtocolError e) {
System.exit(-2);
}
super(baseDirectory, tracker, partsSubdir, logger, scanner);
}
/** Initialize downloader
* @param filename Name of the file to download
*/
protected void initDownloader(String filename) {
downLoader = (ClientDownload) new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger);
}
/** Implementation of writeLog
* @param text Text to log
* @param logLevel level of logging
*/
protected void writeLog(String text, LogLevel logLevel) {
logger.writeUDP(text, logLevel);
}
/** Implementation of Runnable
/** Implementation of writeLog
* @param e exception to log
* @param logLevel level of logging
*/
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:");
String f = scanner.nextLine();
download(f);
System.out.println("File " + f + " sucessfully downloaded");
logger.writeUDP("File " + f + " sucessfully downloaded", LogLevel.Info);
} catch (EmptyDirectory e) {
System.err.println("Error: Server has no file in directory");
logger.writeUDP("Error: Server has no file in directory", LogLevel.Error);
} catch (InternalError e) {
System.err.println("Error: Client internal error");
logger.writeUDP("Error: Client internal error", LogLevel.Error);
} catch (UnknownHostException e) {
System.err.println("Error: Server host is unknown");
logger.writeUDP("Error: Server host is unknown", LogLevel.Error);
} catch (IOException e) {
System.err.println("Error: Request cannot be send or response cannot be received");
logger.writeUDP("Error: Request cannot be send or response cannot be received", LogLevel.Error);
} catch (TransmissionError e) {
System.err.println("Error: Message received is too big");
logger.writeUDP("Error: Message received is too big", LogLevel.Error);
} catch (ProtocolError e) {
System.err.println("Error: Cannot decode servers response");
logger.writeUDP("Error: Cannot decode servers response", LogLevel.Error);
} catch (VersionError e) {
System.err.println("Error: Servers response use bad version of the protocol");
logger.writeUDP("Error: Servers response use bad version of the protocol", LogLevel.Error);
} catch (SizeError e) {
System.err.println("Error: Cannot handle this packets because of internal representation limitations of numbers on the client");
logger.writeUDP("Error: Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error);
} catch (InternalRemoteError e) {
System.err.println("Error: Server internal error");
logger.writeUDP("Error: Server internal error", LogLevel.Error);
} catch (ProtocolRemoteError e) {
System.err.println("Error: Server cannot decode clients request");
logger.writeUDP("Error: Server cannot decode clients request", LogLevel.Error);
} catch (VersionRemoteError e) {
System.err.println("Error: Server cannot decode this version of the protocol");
logger.writeUDP("Error: Server cannot decode this version of the protocol", LogLevel.Error);
} catch (NotFound e) {
System.err.println("Error: Server has not this file in directory");
logger.writeUDP("Error: Server has not this file in directory", LogLevel.Error);
} catch (EmptyFile e) {
System.err.println("Error: File is empty");
logger.writeUDP("Error: File is empty", LogLevel.Error);
}
protected void writeLog(Exception e, LogLevel logLevel) {
logger.writeUDP(e, logLevel);
}
/** 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
/** Create packets
* @param payload Payload
*/
private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
ClientDownloadUDP downLoader = new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger);
Thread t = new Thread(downLoader);
t.start();
try {
t.join();
if (downLoader.getSuccess()) {
byte[] hash512 = downLoader.getHashSum512();
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));
logger.writeUDP("Computed checksum:" + String.format("%02X", b), LogLevel.Info);
}
System.err.println("");
System.err.println("Received checksum:");
for (byte b: hash512) {
System.err.print(String.format("%02X", b));
logger.writeUDP("Received checksum:" + String.format("%02X", b), LogLevel.Info);
}
System.err.println("");
throw new InternalError();
}
} else {
throw new InternalError();
}
} catch (InterruptedException e) {
logger.writeUDP(e, LogLevel.Error);
throw new InternalError();
}
protected < T extends Payload > ProtocolP2PPacket<T> createProtocolP2PPacket(T payload) {
return (ProtocolP2PPacket<T>)new ProtocolP2PPacketUDP<T>(payload);
}
/** 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
/** Getter for tracker socket
*/
private String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
ProtocolP2PPacketUDP<Payload> d = new ProtocolP2PPacketUDP<>(new Payload(RequestResponseCode.LIST_REQUEST));
d.sendRequest((Object)hostList.get(0).getUDPSocket());
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) {
logger.writeUDP(e, LogLevel.Error);
throw new ProtocolError();
} catch (EmptyFile e) {
logger.writeUDP(e, LogLevel.Error);
throw new ProtocolError();
} catch (NotATracker e) {
logger.writeUDP(e, LogLevel.Error);
throw new ProtocolError();
}
protected Object getTrackerSocket() {
return (Object)tracker.getUDPSocket();
}
/** Compute Hashsum of a file.
* @param filename
* @return hashsum
/** Getter for HostItem socket
* @param hostItem HostItem
*/
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");
logger.writeUDP("Error: " + h.getName() + " not supported", LogLevel.Error);
} catch (IOException e) {
System.out.println("Error: cannot read " + filename);
logger.writeUDP("Error: cannot read " + filename, LogLevel.Error);
}
return new byte[0];
protected Object getHostItemSocket(HostItem hostItem) {
return (Object)hostItem.getUDPSocket();
}
/** Initialize hostList from tracker
* @throws ProtocolError
* @throws InternalError
/** Close HostItem socket
* @param hostItem HostItem
*/
private void initHostList() throws ProtocolError, InternalError {
ProtocolP2PPacketUDP<DiscoverRequest> d = new ProtocolP2PPacketUDP<>(new DiscoverRequest(null));
try {
d.sendRequest((Object)tracker.getUDPSocket());
Payload p = d.receiveResponse().getPayload();
assert p instanceof DiscoverResponse : "This payload must be instance of Filelist";
if (!(p instanceof DiscoverResponse)) {
throw new InternalError();
} else {
hostList = ((DiscoverResponse)p).getHostList();
}
} catch (NotATracker e) {
logger.writeUDP(e, LogLevel.Error);
throw new ProtocolError();
} catch (Exception e) {
logger.writeUDP(e, LogLevel.Error);
throw new ProtocolError();
}
protected void closeHostItemSocket(HostItem hostItem) {
hostItem.closeUDPSocket();
}
}

@ -65,10 +65,10 @@ public class ServerManagementTCP extends ServerManagement {
try {
socket = new ServerSocket(server.getPort(), 10, server.getInetAddress());
} catch (SocketException e) {
logger.writeTCP("Error: cannot listen on " + server, LogLevel.Error);
writeLog("Error: cannot listen on " + server, LogLevel.Error);
System.exit(-1);
} catch (IOException e) {
logger.writeTCP("Error: cannot openning socket", LogLevel.Error);
writeLog("Error: cannot openning socket", LogLevel.Error);
System.exit(-2);
}
}
@ -77,7 +77,7 @@ public class ServerManagementTCP extends ServerManagement {
/** Implementation of runnable. This methods allows to run the server.
*/
public void run() {
logger.writeTCP("Server sucessfully started", LogLevel.Info);
writeLog("Server sucessfully started", LogLevel.Info);
fileListWatcher = (FileWatcher)new FileWatcherTCP(logger, 10000, server, tracker, baseDirectory); // checking every 10 seconds
(new Thread(fileListWatcher)).start();
while(!stop) {
@ -86,7 +86,7 @@ public class ServerManagementTCP extends ServerManagement {
ClientHandler c = new ClientHandler(s);
(new Thread(c)).start();
} catch (IOException e) {
logger.writeTCP("Error while accepting new connection", LogLevel.Warning);
writeLog("Error while accepting new connection", LogLevel.Warning);
}
}
fileListWatcher.setStop();
@ -109,11 +109,11 @@ public class ServerManagementTCP extends ServerManagement {
public void run() {
boolean end = false;
logger.writeTCP("[" + addr + "] New connection", LogLevel.Action);
writeLog("[" + addr + "] New connection", LogLevel.Action);
do {
end = handleClientRequest();
} while(!end);
logger.writeTCP("[" + addr + "] End of connection", LogLevel.Action);
writeLog("[" + addr + "] End of connection", LogLevel.Action);
}
/** Respond to next request incomming on socket s.

@ -19,6 +19,13 @@ import localException.InternalError;
import remoteException.EmptyDirectory;
import exception.LocalException;
/** Tracker management implementation
* @author Louis Royer
* @author Flavien Haas
* @author JS Auge
* @version 1.0
*/
public abstract class TrackerManagement extends ServeErrors implements Runnable {
protected HostItem tracker;
protected Logger logger;

@ -46,10 +46,10 @@ public class TrackerManagementTCP extends TrackerManagement {
try {
socket = new ServerSocket(tracker.getPort(), 10, tracker.getInetAddress());
} catch (SocketException e) {
logger.writeTCP("Error: cannot listen on" + tracker, LogLevel.Error);
writeLog("Error: cannot listen on" + tracker, LogLevel.Error);
System.exit(-1);
} catch (IOException e) {
logger.writeTCP("Error: cannot open socket", LogLevel.Error);
writeLog("Error: cannot open socket", LogLevel.Error);
System.exit(-2);
}
}
@ -57,14 +57,14 @@ public class TrackerManagementTCP extends TrackerManagement {
/** Implementation of runnable. This methods allows to run the server.
*/
public void run() {
logger.writeTCP("Tracker sucessfully started", LogLevel.Info);
writeLog("Tracker sucessfully started", LogLevel.Info);
while (!stop) {
try {
Socket s = socket.accept();
ClientHandler c = new ClientHandler(s);
(new Thread(c)).start();
} catch (IOException e) {
logger.writeTCP("Error while accepting new connection", LogLevel.Warning);
writeLog("Error while accepting new connection", LogLevel.Warning);
}
}
}
@ -86,11 +86,11 @@ public class TrackerManagementTCP extends TrackerManagement {
public void run() {
boolean end = false;
logger.writeTCP("[ " + addr + "] New connection", LogLevel.Action);
writeLog("[ " + addr + "] New connection", LogLevel.Action);
do {
end = handleClientRequest();
} while(!end);
logger.writeTCP("[ " + addr + "] End of connection", LogLevel.Action);
writeLog("[ " + addr + "] End of connection", LogLevel.Action);
}
/** Respond to next request incomming on socket s.
@ -102,12 +102,12 @@ public class TrackerManagementTCP extends TrackerManagement {
ProtocolP2PPacketTCP<?> pd = new ProtocolP2PPacketTCP<>((Object)addr.getTCPSocket());
handleRequest(pd);
} catch (IOException e) {
logger.writeTCP(e, LogLevel.Warning);
writeLog(e, LogLevel.Warning);
return true;
} catch (SocketClosed e) {
return true;
} catch (LocalException e) {
logger.writeTCP(e, LogLevel.Warning);
writeLog(e, LogLevel.Warning);
return true;
}
return false;

Loading…
Cancel
Save