Merge pull request 'tracker' (#48) from tracker into etape4
Ajout du tracker, correction de bugs, et documentation.
This commit is contained in:
commit
e0dca481fb
@ -17,17 +17,22 @@ x bytes: [(bytes 8-?): PAYLOAD]
|
||||
- `LIST` (0x00)
|
||||
- `LOAD` (0x01)
|
||||
- `HASH` (0x02)
|
||||
- `DISCOVER` (0x03)
|
||||
- `REGISTER` (0x04)
|
||||
- `UNREGISTER` (0x05)
|
||||
|
||||
- RESPONSES (msb is 1):
|
||||
- `LIST` (0x80)
|
||||
- `LOAD` (0x81)
|
||||
- `HASH` (0x82)
|
||||
- `DISCOVER` (0x83)
|
||||
- `VERSION ERROR` (0xC0)
|
||||
- `PROTOCOL ERROR` (0xC1)
|
||||
- `INTERNAL ERROR` (0xC2)
|
||||
- `EMPTY DIRECTORY` (0xC3)
|
||||
- `NOT FOUND` (0xC4)
|
||||
- `EMPTY FILE` (0xC5)
|
||||
- `NOT A TRACKER` (0xC6)
|
||||
|
||||
### List
|
||||
Payload size for list request is always zero.
|
||||
@ -97,6 +102,55 @@ A algo hash bloc contains:
|
||||
|
||||
```
|
||||
|
||||
### Tracker specific messages
|
||||
#### Register
|
||||
Used by a server to register itself on a tracker.
|
||||
Server may want to do a free `DISCOVER` to check if they have been registered.
|
||||
Payload contains:
|
||||
|
||||
```
|
||||
2 bytes: [<PORT NUMBER>]
|
||||
```
|
||||
|
||||
#### Unregister
|
||||
Used by a server to unregister itself from a tracker.
|
||||
No error is raised if the server was not registered.
|
||||
Server may want to do a free `DISCOVER` to check if they have been unregistered.
|
||||
Payload contains:
|
||||
|
||||
```
|
||||
2 bytes: [<PORT NUMBER>]
|
||||
? bytes: [<HOSTNAME>]
|
||||
```
|
||||
|
||||
#### Discover request
|
||||
If payload size is null, lists all servers registered.
|
||||
If payload contains a filename, list all servers having this file in their list.
|
||||
|
||||
```
|
||||
? bytes: [<FILENAME>]
|
||||
? bytes: [<HOSTNAME>]
|
||||
```
|
||||
|
||||
#### Discover response
|
||||
Contains:
|
||||
```
|
||||
4 bytes: [(bytes 8-11): FILENAME SIZE]
|
||||
y bytes: [<FILENAME>]
|
||||
? bytes [multiple server blocks]
|
||||
```
|
||||
|
||||
Server block is composed with:
|
||||
|
||||
```
|
||||
2 bytes: [port]
|
||||
? bytes: hostname
|
||||
\n
|
||||
```
|
||||
|
||||
#### Not a Tracker
|
||||
This error is raised when receiving a DISCOVER, a REGISTER, or an UNREGISTER request,
|
||||
but this application is not a tracker.
|
||||
|
||||
### Other response code (errors)
|
||||
#### Version error
|
||||
|
1
doc/tracker_sequence_diagram.drawio
Normal file
1
doc/tracker_sequence_diagram.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2020-03-19T14:50:01.302Z" agent="Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0" etag="dOXguTcOAZ-R9XuIfENW" version="12.8.8" type="device"><diagram name="Page-1" id="13e1069c-82ec-6db2-03f1-153e76fe0fe0">7Vtfc+I2EP80zFwfkrEt28BjQkh60+tdEtJrp2/CFqBGWFSI/LlP3xWWDZbAEJ8hZpo8MNJqvZJ2f1rtSkoL9aYvNwLPJr/zmLCW58QvLXTV8rxO2IFfRXhNCX63mxLGgsYpyV0RBvQH0URHUxc0JvMCo+ScSTorEiOeJCSSBRoWgj8X2UacFXud4TGxCIMIM5v6J43lRFNdx1k1/EroeKK77gS6YYijx7Hgi0T31/LQaPmXNk9xJkvzzyc45s9rJNRvoZ7gXKal6UuPMKXaTG3pd9dbWvNxC5LIfT5oD/EQu5E/jLz2yB86Z14q4QmzhdbFg4A5EaHHK18zHcHQZ6q4mLIvdEQYTaB2OSOCTokEfnTFNPl2Rbt8nlBJBjMcqU+fATxAm8gpg5oLRTCoxPCJyOuM4dmcDpe9OkARJFqIOX0i92Se4kZR+UKqnno5Hpasyg4k1qJyVTtLuVMa6TLDQ8Iuc8P1OOOq+4QvJzSXgj/mKFCCRjDGazylTIH7OxExTrAmayS7YMdLzOg4gUoEplhO3baNNtcTEZK8rJG0rW4IB7WJV2DRrZ6vcaPXVUdXn9dAmmF0sobPIGPEemGMc9ErcEBB42NPrCALKz1GYXLuB1YagBXfaRJW2hZWWuji2/AfZYEPtLw/Wrphk9DSsdAyIAIm8+FZmoAVt1GexQ8tsHzlkmxFSqIad0JAW9X1oaw0QyE4vNC6lHy2pllGRlJ9AKJoMn5QbVdnYcHwztENX79DQHsaGQU12Lj9RzIVf9Hf/h7Iq3+vF/0wnm6ITO/7N58HD/37T79Yxl6zpGm9IZeST6GBJPGFyhUUjfHosWxxSCzGRG5BoB4ZiQtJha3ZNdVlK0EQhiW4kUJnm1Snpd1yCiNbrcSgaCQ3NFbYnC9ERPRX63mAISg37zZBqQIsQUtL5lOsblzfMu4XMC1Q7vt3lYw7hwHLzLwc5Ga0a8qyjzcAYMmil1GnMiA6bwdEWA8gvG7Rjp5TERAo2CFoCyBAofh1jW2mGOYlA+5s7meFr1RirWgLtqNtcPtpRBkBxffUwQEUvWre5V0BuK9H0kZwzl2/bbn3miBp+qg8h32zj3J3CNoCyZWgjJGPRnNyED/WtZB19XnQ+/a9f5+ha54FsgpfacVbr6Bmwi01UjncSiGJ3s0nItMnmmHovgD0TSSbgmryiabv9dERfGK2uKycy7Pw+JFzHT/nCoL3zLk2Asa1APOTAflJbJn1+6fQqSmID8P3DeKzvPNEo/gyr9iEUL4qLKxQ/siw2HD064VMnZnE9AmKY1UshEl3yoGkLNDjGlcjQVQaGqFGux4roulWxFhgxuamoJpCI98r9oPaTum4svYt/AcKpeyLMTO/9Fb55SkE/GWusanQNnbVymmnH+4QVBO0A/PA1by6N8eFSvkPBO3/50GdVvmZc+6gUAs+AGSN232/sjd2dghqwEmJax/CpfkmsmD0kW8eP98MjY2zAfmmfc/X8Hxz9xYanNQWmu0wP72FWoJq2kJDw4G63WNsifZjhVPaEstw2YSstyrmrKx3T8zVBgv7KqDkkulkk4APD1ZvEmAG9f6O/LZTyn8Yj5fNfb/8tqH3p6WnNp09UL3vhVZ+x+o4CBW3JzumquvO1cxZg4q497rd86BcVF0PAYwTpCyQ3Dqydil/Efm2gopzOFyak0feW26E72C5RBNKxCkuk4YfbppZsFuT87cE1XXvaxxuhsc40fE8C6BfASpg1QmB32j5oh8Kj4n6r5rslYKrppXEeR2pNBA/Ee3zAXUXUIQsOGEcK7YIJ/A7JGOanFtAP/rTzK1wf8MjWMP/hBsy5MyAhQy5bYCnvgeS9rHzHo9PTiHyPK33JqbfCaq+wTNPeMMDbb3muWN2j1zR70B19Q9sKfvqnwRR/z8=</diagram></mxfile>
|
3
doc/tracker_sequence_diagram.svg
Normal file
3
doc/tracker_sequence_diagram.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 29 KiB |
@ -5,7 +5,6 @@ import java.net.Socket;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import protocolP2P.ProtocolP2PPacketTCP;
|
||||
import protocolP2P.Payload;
|
||||
import protocolP2P.LoadRequest;
|
||||
@ -22,6 +21,7 @@ import remoteException.InternalRemoteError;
|
||||
import remoteException.VersionRemoteError;
|
||||
import remoteException.ProtocolRemoteError;
|
||||
import remoteException.NotFound;
|
||||
import remoteException.NotATracker;
|
||||
import tools.Logger;
|
||||
import tools.LogLevel;
|
||||
|
||||
@ -351,6 +351,10 @@ public class ClientDownloadPartTCP implements Runnable {
|
||||
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;
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ import remoteException.ProtocolRemoteError;
|
||||
import localException.VersionError;
|
||||
import localException.SizeError;
|
||||
import remoteException.NotFound;
|
||||
import remoteException.NotATracker;
|
||||
import java.nio.file.Files;
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.io.IOException;
|
||||
import tools.Logger;
|
||||
import tools.LogLevel;
|
||||
@ -336,6 +336,10 @@ public class ClientDownloadPartUDP implements Runnable {
|
||||
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;
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import java.util.Random;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import remoteException.EmptyDirectory;
|
||||
@ -16,6 +15,7 @@ import remoteException.VersionRemoteError;
|
||||
import remoteException.ProtocolRemoteError;
|
||||
import remoteException.NotFound;
|
||||
import remoteException.InternalRemoteError;
|
||||
import remoteException.NotATracker;
|
||||
import localException.ProtocolError;
|
||||
import localException.InternalError;
|
||||
import localException.TransmissionError;
|
||||
@ -239,6 +239,9 @@ public class ClientDownloadTCP implements Runnable {
|
||||
} 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) {
|
||||
@ -382,6 +385,9 @@ public class ClientDownloadTCP implements Runnable {
|
||||
} 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);
|
||||
|
@ -7,7 +7,6 @@ import java.util.Random;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import localException.ProtocolError;
|
||||
@ -21,6 +20,7 @@ import remoteException.VersionRemoteError;
|
||||
import remoteException.ProtocolRemoteError;
|
||||
import remoteException.NotFound;
|
||||
import remoteException.InternalRemoteError;
|
||||
import remoteException.NotATracker;
|
||||
import protocolP2P.HashAlgorithm;
|
||||
import protocolP2P.HashResponse;
|
||||
import protocolP2P.HashRequest;
|
||||
@ -239,6 +239,9 @@ public class ClientDownloadUDP implements Runnable {
|
||||
} 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) {
|
||||
@ -378,6 +381,9 @@ public class ClientDownloadUDP implements Runnable {
|
||||
} 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);
|
||||
|
@ -4,9 +4,7 @@ import java.net.UnknownHostException;
|
||||
import java.util.Scanner;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.security.MessageDigest;
|
||||
@ -23,19 +21,18 @@ 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.FilePart;
|
||||
import protocolP2P.LoadRequest;
|
||||
import protocolP2P.HashAlgorithm;
|
||||
import protocolP2P.HashRequest;
|
||||
import protocolP2P.HashResponse;
|
||||
import clientP2P.ClientDownloadTCP;
|
||||
import tools.HostItem;
|
||||
import tools.Logger;
|
||||
import tools.LogLevel;
|
||||
import protocolP2P.DiscoverRequest;
|
||||
import protocolP2P.DiscoverResponse;
|
||||
|
||||
/** Implementation of P2P-JAVA-PROJECT CLIENT
|
||||
* @author Louis Royer
|
||||
@ -47,26 +44,36 @@ public class ClientManagementTCP implements Runnable {
|
||||
private String baseDirectory;
|
||||
private String partsSubdir;
|
||||
private List<HostItem> hostList;
|
||||
private HostItem tracker;
|
||||
private Logger logger;
|
||||
private Scanner scanner;
|
||||
|
||||
/** Constructor for TCP implementation, with baseDirectory and TCPPort parameters.
|
||||
/** Constructor for TCP implementation, with baseDirectory, tracker, partsSubdir, logger, and scanner parameters.
|
||||
* @param baseDirectory the root directory where files are stored
|
||||
* @param host hostname of the server
|
||||
* @param TCPPort the server will listen on this port
|
||||
* @param tracker Tracker hostItem
|
||||
* @param partsSubdir subdirectory to store file parts
|
||||
* @param logger Loggger
|
||||
* @param scanner Scanner used to read input
|
||||
*/
|
||||
public ClientManagementTCP(String baseDirectory, List<HostItem> hostList, String partsSubdir, Logger logger) {
|
||||
public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) {
|
||||
this.scanner = scanner;
|
||||
this.baseDirectory = baseDirectory;
|
||||
this.hostList = hostList;
|
||||
this.tracker = tracker;
|
||||
this.partsSubdir = partsSubdir;
|
||||
this.logger = logger;
|
||||
try {
|
||||
initHostList();
|
||||
} catch (InternalError e) {
|
||||
System.exit(-1);
|
||||
} catch (ProtocolError e) {
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of Runnable
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println("Enter all servers: type \"stop\" when finished");
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
String[] list = listDirectory();
|
||||
System.out.println("Files present on the server:");
|
||||
for(String listItem: list) {
|
||||
@ -78,44 +85,31 @@ public class ClientManagementTCP implements Runnable {
|
||||
System.out.println("File " + f + " sucessfully downloaded");
|
||||
logger.writeTCP("File " + f + " sucessfully downloaded", LogLevel.Info);
|
||||
} catch (EmptyDirectory e) {
|
||||
System.err.println("Error: Server has no file in directory");
|
||||
logger.writeTCP("Error: Server has no file in directory", LogLevel.Error);
|
||||
logger.writeTCP("Server has no file in directory", LogLevel.Error);
|
||||
} catch (InternalError e) {
|
||||
System.err.println("Error: Client internal error");
|
||||
logger.writeTCP("Error: Client internal error", LogLevel.Error);
|
||||
logger.writeTCP("Client internal error", LogLevel.Error);
|
||||
} catch (UnknownHostException e) {
|
||||
System.err.println("Error: Server host is unknown");
|
||||
logger.writeTCP("Error: Server host is unknown", LogLevel.Error);
|
||||
logger.writeTCP("Server host is unknown", LogLevel.Error);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error: Request cannot be send or response cannot be received");
|
||||
logger.writeTCP("Error: Request cannot be send or response cannot be received", LogLevel.Error);
|
||||
logger.writeTCP("Request cannot be send or response cannot be received", LogLevel.Error);
|
||||
} catch (TransmissionError e) {
|
||||
System.err.println("Error: Message received is too big");
|
||||
logger.writeTCP("Error: Message received is too big", LogLevel.Error);
|
||||
logger.writeTCP("Message received is too big", LogLevel.Error);
|
||||
} catch (ProtocolError e) {
|
||||
System.err.println("Error: Cannot decode server’s response");
|
||||
logger.writeTCP("Error: Cannot decode server’s response", LogLevel.Error);
|
||||
logger.writeTCP("Cannot decode server’s response", LogLevel.Error);
|
||||
} catch (VersionError e) {
|
||||
System.err.println("Error: Server’s response use bad version of the protocol");
|
||||
logger.writeTCP("Error: Server’s response use bad version of the protocol", LogLevel.Error);
|
||||
logger.writeTCP("Server’s 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.writeTCP("Error: Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error);
|
||||
logger.writeTCP("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.writeTCP("Error: Server internal error", LogLevel.Error);
|
||||
logger.writeTCP("Server internal error", LogLevel.Error);
|
||||
} catch (ProtocolRemoteError e) {
|
||||
System.err.println("Error: Server cannot decode client’s request");
|
||||
logger.writeTCP("Error: Server cannot decode client’s request", LogLevel.Error);
|
||||
logger.writeTCP("Server cannot decode client’s request", LogLevel.Error);
|
||||
} catch (VersionRemoteError e) {
|
||||
System.err.println("Error: Server cannot decode this version of the protocol");
|
||||
logger.writeTCP("Error: Server cannot decode this version of the protocol", LogLevel.Error);
|
||||
logger.writeTCP("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.writeTCP("Error: Server has not this file in directory", LogLevel.Error);
|
||||
logger.writeTCP("Server has not this file in directory", LogLevel.Error);
|
||||
} catch (EmptyFile e) {
|
||||
System.err.println("Error: File is empty");
|
||||
logger.writeTCP("Error: File is empty", LogLevel.Error);
|
||||
logger.writeTCP("File is empty", LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,21 +137,18 @@ public class ClientManagementTCP implements Runnable {
|
||||
if (downLoader.getSuccess()) {
|
||||
byte[] hash512 = downLoader.getHashSum512();
|
||||
if (!Arrays.equals(hash512, computeHashsum(filename, HashAlgorithm.SHA512))) {
|
||||
System.err.println("Error: Hashsum does not match");
|
||||
logger.writeTCP("Error: Hashsum does not match", LogLevel.Error);
|
||||
System.err.println("Computed checksum:");
|
||||
logger.writeTCP("Hashsum does not match", LogLevel.Error);
|
||||
String line = "Computed checksum:\n";
|
||||
byte[] c = computeHashsum(filename, HashAlgorithm.SHA512);
|
||||
for (byte b: c) {
|
||||
System.err.print(String.format("%02X", b));
|
||||
logger.writeTCP("Computed checksum:" + String.format("%02X", b), LogLevel.Info);
|
||||
line += String.format("%02X", b);
|
||||
}
|
||||
System.err.println("");
|
||||
System.err.println("Received checksum:");
|
||||
line += "\nReceived checksum:\n";
|
||||
for (byte b: hash512) {
|
||||
System.err.print(String.format("%02X", b));
|
||||
logger.writeTCP("Received checksum:" + String.format("%02X", b), LogLevel.Info);
|
||||
line += String.format("%02X", b);
|
||||
}
|
||||
System.err.println("");
|
||||
line += "\n";
|
||||
logger.writeTCP(line, LogLevel.Info);
|
||||
throw new InternalError();
|
||||
}
|
||||
} else {
|
||||
@ -200,9 +191,11 @@ public class ClientManagementTCP implements Runnable {
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
throw new ProtocolError();
|
||||
} catch (SocketClosed e){
|
||||
System.err.println("listDirectory : SocketClosed");
|
||||
logger.writeTCP("listDirectory : SocketClosed", LogLevel.Error);
|
||||
throw new ProtocolError();
|
||||
} catch (NotATracker e) {
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
throw new ProtocolError();
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,12 +208,37 @@ public class ClientManagementTCP implements Runnable {
|
||||
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.writeTCP("Error: " + h.getName() + " not supported", LogLevel.Error);
|
||||
logger.writeTCP(h.getName() + " not supported", LogLevel.Error);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error: cannot read " + filename);
|
||||
logger.writeTCP("Error: cannot read " + filename, LogLevel.Error);
|
||||
logger.writeTCP("cannot read " + filename, LogLevel.Error);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
/** Initialize hostList from tracker
|
||||
* @throws ProtocolError
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void initHostList() throws ProtocolError, InternalError {
|
||||
ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP((Payload) 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,9 @@ import java.util.Scanner;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import localException.InternalError;
|
||||
@ -23,15 +20,14 @@ 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.FilePart;
|
||||
import protocolP2P.LoadRequest;
|
||||
import protocolP2P.HashAlgorithm;
|
||||
import protocolP2P.HashRequest;
|
||||
import protocolP2P.HashResponse;
|
||||
import protocolP2P.DiscoverRequest;
|
||||
import protocolP2P.DiscoverResponse;
|
||||
import tools.HostItem;
|
||||
import tools.Logger;
|
||||
import tools.LogLevel;
|
||||
@ -47,26 +43,36 @@ public class ClientManagementUDP implements Runnable {
|
||||
private String baseDirectory;
|
||||
private String partsSubdir;
|
||||
private List<HostItem> hostList;
|
||||
private HostItem tracker;
|
||||
private Logger logger;
|
||||
private Scanner scanner;
|
||||
|
||||
/** Constructor for UDP implementation, with baseDirectory and UDPPort parameters.
|
||||
/** Constructor for UDP implementation, with baseDirectory, tracker, partsSubdir, logger and scanner parameters.
|
||||
* @param baseDirectory the root directory where files are stored
|
||||
* @param host hostname of the server
|
||||
* @param UDPPort the server will listen on this port
|
||||
* @param tracker tracker HostItem
|
||||
* @param partsSubdir subdirectory to store file parts
|
||||
* @param logger Loggger
|
||||
* @param scanner Scanner used to read input
|
||||
*/
|
||||
public ClientManagementUDP(String baseDirectory, List<HostItem> hostList, String partsSubdir, Logger logger) {
|
||||
public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) {
|
||||
this.scanner = scanner;
|
||||
this.baseDirectory = baseDirectory;
|
||||
this.hostList = hostList;
|
||||
this.tracker = tracker;
|
||||
this.partsSubdir = partsSubdir;
|
||||
this.logger = logger;
|
||||
try {
|
||||
initHostList();
|
||||
} catch (InternalError e) {
|
||||
System.exit(-1);
|
||||
} catch (ProtocolError e) {
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of Runnable
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println("Enter all servers: type \"stop\" when finished");
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
String[] list = listDirectory();
|
||||
System.out.println("Files present on the server:");
|
||||
for(String listItem: list) {
|
||||
@ -199,6 +205,9 @@ public class ClientManagementUDP implements Runnable {
|
||||
} catch (EmptyFile e) {
|
||||
logger.writeUDP(e, LogLevel.Error);
|
||||
throw new ProtocolError();
|
||||
} catch (NotATracker e) {
|
||||
logger.writeUDP(e, LogLevel.Error);
|
||||
throw new ProtocolError();
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,4 +228,28 @@ public class ClientManagementUDP implements Runnable {
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
/** Initialize hostList from tracker
|
||||
* @throws ProtocolError
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void initHostList() throws ProtocolError, InternalError {
|
||||
ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP((Payload) 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,10 @@ import clientP2P.ClientManagementUDP;
|
||||
import clientP2P.ClientManagementTCP;
|
||||
import serverP2P.ServerManagementUDP;
|
||||
import serverP2P.ServerManagementTCP;
|
||||
import tools.Directories;
|
||||
import tools.Logger;
|
||||
import tools.LogLevel;
|
||||
import tools.Directories;
|
||||
import tools.HostItem;
|
||||
import tools.HostList;
|
||||
|
||||
/** Client + Server implementation.
|
||||
* @author Louis Royer
|
||||
@ -21,15 +19,16 @@ import tools.HostList;
|
||||
*/
|
||||
|
||||
public class ClientP2P {
|
||||
static private final String subdir = "seeded/";
|
||||
static private String parts = ".parts";
|
||||
private String subdir = "seeded/";
|
||||
private String parts = ".parts";
|
||||
private Logger loggerServer;
|
||||
private Logger loggerClient;
|
||||
private String host;
|
||||
private int port;
|
||||
private Directories directories;
|
||||
private List<HostItem> hostList;
|
||||
private static final int defaultPort = 20000;
|
||||
private HostItem tracker;
|
||||
private Scanner scanner;
|
||||
|
||||
|
||||
/** Initialize loggers if directories and logger are null,
|
||||
@ -47,6 +46,8 @@ public class ClientP2P {
|
||||
* @param portStr String containing port for server listenning.
|
||||
*/
|
||||
public ClientP2P(String portStr) {
|
||||
scanner = new Scanner(System.in);
|
||||
tracker = new HostItem("localhost", 30000); // TODO : make it configurable
|
||||
try{
|
||||
port = Integer.valueOf(Integer.parseInt(portStr));
|
||||
} catch (NumberFormatException e){
|
||||
@ -61,7 +62,7 @@ public class ClientP2P {
|
||||
directories.createSubdir(parts);
|
||||
host = "localhost";
|
||||
System.out.println("Server will listen on port " + port + " and serve files from " + directories.getDataHomeDirectory() + subdir);
|
||||
directories.askOpenDataHomeDirectory(subdir);
|
||||
directories.askOpenDataHomeDirectory(subdir, scanner);
|
||||
System.out.println("Please enter list of servers to use; first one will be used to ask list of files");
|
||||
}
|
||||
|
||||
@ -71,7 +72,6 @@ public class ClientP2P {
|
||||
* @param args server listenning port
|
||||
*/
|
||||
public static void main(String [] args) {
|
||||
|
||||
if (args[1].equals("help") || args[1].equals("-h") || args[1].equals("h")){
|
||||
System.out.println("usage : java -ea clientP2P.ClientP2P -- <PORT> ");
|
||||
}
|
||||
@ -84,8 +84,8 @@ public class ClientP2P {
|
||||
}
|
||||
|
||||
// Server threads
|
||||
ServerManagementUDP smudp = new ServerManagementUDP(c.directories.getDataHomeDirectory() + subdir, c.port, c.loggerServer);
|
||||
ServerManagementTCP smtcp = new ServerManagementTCP(c.directories.getDataHomeDirectory() + subdir, c.port, c.loggerServer);
|
||||
ServerManagementUDP smudp = new ServerManagementUDP(c.directories.getDataHomeDirectory() + c.subdir, "localhost", c.port, c.loggerServer, c.tracker);
|
||||
ServerManagementTCP smtcp = new ServerManagementTCP(c.directories.getDataHomeDirectory() + c.subdir, "localhost", c.port, c.loggerServer, c.tracker);
|
||||
Thread tudp = new Thread(smudp);
|
||||
tudp.setName("server UDP P2P-JAVA-PROJECT (port: " + c.port + ")");
|
||||
tudp.start();
|
||||
@ -102,10 +102,9 @@ public class ClientP2P {
|
||||
}
|
||||
|
||||
// initialize Host lists
|
||||
c.hostList = HostList.getServList();
|
||||
System.out.println("Client : Which transport protocol do you want to use? [TCP/udp]");
|
||||
Scanner sc = new Scanner(System.in);
|
||||
String transportchoosen = sc.nextLine();
|
||||
c.scanner.hasNextLine();
|
||||
String transportchoosen = c.scanner.nextLine();
|
||||
Thread t;
|
||||
switch(transportchoosen){
|
||||
case "UDP":
|
||||
@ -113,7 +112,7 @@ public class ClientP2P {
|
||||
case "upd": // alias typo
|
||||
case "2" :
|
||||
System.out.println("Starting with UDP");
|
||||
ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.hostList, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient);
|
||||
ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient, c.scanner);
|
||||
t = new Thread(cmudp);
|
||||
break;
|
||||
case "TCP":
|
||||
@ -121,13 +120,16 @@ public class ClientP2P {
|
||||
case "1":
|
||||
default:
|
||||
System.out.println("Starting with TCP");
|
||||
ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.hostList, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient);
|
||||
ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient, c.scanner);
|
||||
t = new Thread(cmtcp);
|
||||
break;
|
||||
}
|
||||
|
||||
t.setName("client P2P-JAVA-PROJECT");
|
||||
t.start();
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException e) {}
|
||||
c.scanner.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package localException;
|
||||
|
||||
import exception.LocalException;
|
||||
|
||||
public class InternalError extends exception.LocalException {
|
||||
public class InternalError extends LocalException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package localException;
|
||||
|
||||
import exception.LocalException;
|
||||
|
||||
public class ProtocolError extends exception.LocalException {
|
||||
public class ProtocolError extends LocalException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ import exception.LocalException;
|
||||
|
||||
|
||||
/** Used on reception side when size as set in Packet is too big, and we cant store this in a int/long as usual. */
|
||||
public class SizeError extends exception.LocalException {
|
||||
public class SizeError extends LocalException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package localException;
|
||||
|
||||
import exception.LocalException;
|
||||
|
||||
public class SocketClosed extends exception.LocalException {
|
||||
public class SocketClosed extends LocalException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package localException;
|
||||
|
||||
import exception.LocalException;
|
||||
|
||||
public class TransmissionError extends exception.LocalException {
|
||||
public class TransmissionError extends LocalException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package localException;
|
||||
|
||||
import exception.LocalException;
|
||||
|
||||
public class VersionError extends exception.LocalException {
|
||||
public class VersionError extends LocalException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ package protocolP2P;
|
||||
*/
|
||||
public enum CodeType {
|
||||
REQUEST,
|
||||
REQUEST_TRACKER,
|
||||
RESPONSE,
|
||||
ERROR
|
||||
}
|
||||
|
71
src/protocolP2P/DiscoverRequest.java
Normal file
71
src/protocolP2P/DiscoverRequest.java
Normal file
@ -0,0 +1,71 @@
|
||||
package protocolP2P;
|
||||
import protocolP2P.Payload;
|
||||
import tools.BytesArrayTools;
|
||||
import localException.InternalError;
|
||||
import localException.SizeError;
|
||||
import localException.ProtocolError;
|
||||
import localException.TransmissionError;
|
||||
|
||||
/** Representation of payload for discover request.
|
||||
* @author Louis Royer
|
||||
* @author Flavien Haas
|
||||
* @author JS Auge
|
||||
* @version 1.0
|
||||
*/
|
||||
public class DiscoverRequest extends Payload {
|
||||
|
||||
private String filename;
|
||||
|
||||
/** Constructor with filename (typically used by client). If filename is null, it is initialized with "".
|
||||
* @param filename Name of the file you want a server list of.
|
||||
* @throws InternalError
|
||||
*/
|
||||
public DiscoverRequest(String filename) throws InternalError {
|
||||
super(RequestResponseCode.DISCOVER_REQUEST);
|
||||
if (filename == null) {
|
||||
this.filename = "";
|
||||
} else {
|
||||
this.filename = filename;
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructor (typically used by server) with a byte[] parameter containing the Packet received.
|
||||
* @param packet the full Packet received
|
||||
* @throws SizeError
|
||||
* @throws InternalError
|
||||
* @throws ProtocolError
|
||||
* @throws TransmissionError
|
||||
*/
|
||||
protected DiscoverRequest(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError {
|
||||
super(packet);
|
||||
int size = getPayloadSize(packet);
|
||||
filename = BytesArrayTools.readString(packet, Payload.PAYLOAD_START_POSITION, size);
|
||||
}
|
||||
|
||||
/** Returns a byte[] containing Packet with padding.
|
||||
* This Packet is still incomplete and should not be send directly.
|
||||
* ProtocolP2PPacket will use this method to generate the complete Packet.
|
||||
* @return Packet with padding
|
||||
* @throws InternalError
|
||||
*/
|
||||
protected byte[] toPacket() throws InternalError {
|
||||
// compute total size
|
||||
int size = PAYLOAD_START_POSITION + filename.length();
|
||||
byte[] packet = new byte[size + 1]; // java initialize all to zero
|
||||
// set request/response code
|
||||
packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
|
||||
// set Payload size
|
||||
setPayloadSize(size - PAYLOAD_START_POSITION, packet);
|
||||
// write filename to Packet
|
||||
BytesArrayTools.write(packet, filename, PAYLOAD_START_POSITION);
|
||||
return packet;
|
||||
}
|
||||
|
||||
/** Filename getter.
|
||||
* @return filename
|
||||
*/
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
}
|
117
src/protocolP2P/DiscoverResponse.java
Normal file
117
src/protocolP2P/DiscoverResponse.java
Normal file
@ -0,0 +1,117 @@
|
||||
package protocolP2P;
|
||||
import protocolP2P.Payload;
|
||||
import tools.HostItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import localException.InternalError;
|
||||
import localException.SizeError;
|
||||
import localException.ProtocolError;
|
||||
import localException.TransmissionError;
|
||||
import tools.BytesArrayTools;
|
||||
|
||||
/** Representation of payload for discover response.
|
||||
* @author Louis Royer
|
||||
* @author Flavien Haas
|
||||
* @author JS Auge
|
||||
* @version 1.0
|
||||
*/
|
||||
public class DiscoverResponse extends Payload {
|
||||
|
||||
private List<HostItem> hostList;
|
||||
private String filename;
|
||||
private static final int FILENAME_SIZE_POSITION = PAYLOAD_START_POSITION;
|
||||
private static final int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4;
|
||||
|
||||
/** Constructor with filename (typically used by tracker). If filename is null, it is initialized with "".
|
||||
* @param filename Name of the file related to the server list.
|
||||
* @param hostList List of servers
|
||||
* @throws InternalError
|
||||
*/
|
||||
public DiscoverResponse(String filename, List<HostItem> hostList) throws InternalError {
|
||||
super(RequestResponseCode.DISCOVER_RESPONSE);
|
||||
this.filename = filename;
|
||||
this.hostList = hostList;
|
||||
}
|
||||
|
||||
/** Constructor (typically used by server) with a byte[] parameter containing the Packet received.
|
||||
* @param packet the full Packet received
|
||||
* @throws SizeError
|
||||
* @throws InternalError
|
||||
* @throws ProtocolError
|
||||
* @throws TransmissionError
|
||||
*/
|
||||
protected DiscoverResponse(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError {
|
||||
super(packet);
|
||||
int size = getPayloadSize(packet);
|
||||
/* Read filename size */
|
||||
int filenameSize = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION);
|
||||
|
||||
/* Read filename */
|
||||
filename = BytesArrayTools.readString(packet, FILENAME_POSITION, filenameSize);
|
||||
|
||||
// TODO
|
||||
hostList = new ArrayList<>();
|
||||
int i = FILENAME_POSITION + filenameSize;
|
||||
while(i<size) {
|
||||
int port = BytesArrayTools.readInt16Bits(packet, i);
|
||||
i += 2;
|
||||
String hostname = BytesArrayTools.readString(packet, i, "\n");
|
||||
i += hostname.length();
|
||||
hostList.add(new HostItem(hostname, port));
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a byte[] containing Packet with padding.
|
||||
* This Packet is still incomplete and should not be send directly.
|
||||
* ProtocolP2PPacket will use this method to generate the complete Packet.
|
||||
* @return Packet with padding
|
||||
* @throws InternalError
|
||||
*/
|
||||
protected byte[] toPacket() throws InternalError {
|
||||
int filenameSize = filename.length();
|
||||
int hostListSize = 0;
|
||||
for (HostItem hostItem: hostList) {
|
||||
hostListSize += (2 + hostItem.getHostname().length() + 1);
|
||||
}
|
||||
// compute total size
|
||||
int size = FILENAME_POSITION + filename.length() + hostListSize;
|
||||
byte[] packet = new byte[size + 1]; // java initialize all to zero
|
||||
// set request/response code
|
||||
packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
|
||||
// set Payload size
|
||||
setPayloadSize(size - PAYLOAD_START_POSITION, packet);
|
||||
// write filename size
|
||||
BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filenameSize);
|
||||
// write filename
|
||||
BytesArrayTools.write(packet, filename, FILENAME_POSITION);
|
||||
|
||||
int i = FILENAME_POSITION + filename.length();
|
||||
// write hostList
|
||||
for(HostItem hostItem: hostList) {
|
||||
try {
|
||||
BytesArrayTools.write16Bits(packet, i, hostItem.getPort());
|
||||
i+=2;
|
||||
String hostname = hostItem.getHostname() + "\n";
|
||||
BytesArrayTools.write(packet, hostname, i);
|
||||
i+=hostname.length();
|
||||
} catch (SizeError e) {
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
/** HostList getter.
|
||||
* @return hostList
|
||||
*/
|
||||
public List<HostItem> getHostList() {
|
||||
return hostList;
|
||||
}
|
||||
|
||||
/** Filename getter.
|
||||
* @return filename
|
||||
*/
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
package protocolP2P;
|
||||
import java.util.Arrays;
|
||||
import protocolP2P.Payload;
|
||||
import protocolP2P.RequestResponseCode;
|
||||
import localException.TransmissionError;
|
||||
import localException.ProtocolError;
|
||||
import localException.InternalError;
|
||||
import localException.SizeError;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import tools.BytesArrayTools;
|
||||
|
||||
/** Representation of payload for list response.
|
||||
|
@ -6,8 +6,6 @@ import localException.InternalError;
|
||||
import localException.SizeError;
|
||||
import localException.TransmissionError;
|
||||
import tools.BytesArrayTools;
|
||||
import java.util.Arrays;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/** Representation of payload for load response.
|
||||
* @author Louis Royer
|
||||
@ -83,7 +81,7 @@ public class FilePart extends Payload {
|
||||
// set request/response code
|
||||
packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
|
||||
// set Payload size
|
||||
setPayloadSize(size - OFFSET_POSITION, packet);
|
||||
setPayloadSize(size - PAYLOAD_START_POSITION, packet);
|
||||
// write offset to Packet
|
||||
BytesArrayTools.write(packet, OFFSET_POSITION, offset);
|
||||
// write totalSize to Packet
|
||||
|
@ -1,7 +1,6 @@
|
||||
package protocolP2P;
|
||||
import protocolP2P.Payload;
|
||||
import protocolP2P.HashAlgorithm;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import localException.TransmissionError;
|
||||
import localException.SizeError;
|
||||
import localException.ProtocolError;
|
||||
|
@ -2,7 +2,6 @@ package protocolP2P;
|
||||
import protocolP2P.Payload;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import localException.TransmissionError;
|
||||
import localException.SizeError;
|
||||
import localException.ProtocolError;
|
||||
|
@ -6,7 +6,6 @@ import localException.ProtocolError;
|
||||
import localException.InternalError;
|
||||
import localException.SizeError;
|
||||
import tools.BytesArrayTools;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/** Representation of payload for load request.
|
||||
* @author Louis Royer
|
||||
|
@ -5,6 +5,10 @@ import protocolP2P.FileList;
|
||||
import protocolP2P.LoadRequest;
|
||||
import protocolP2P.HashRequest;
|
||||
import protocolP2P.HashResponse;
|
||||
import protocolP2P.DiscoverRequest;
|
||||
import protocolP2P.DiscoverResponse;
|
||||
import protocolP2P.Register;
|
||||
import protocolP2P.Unregister;
|
||||
import localException.ProtocolError;
|
||||
import localException.InternalError;
|
||||
import localException.TransmissionError;
|
||||
@ -27,11 +31,15 @@ public class Payload {
|
||||
*/
|
||||
public Payload(RequestResponseCode requestResponseCode) throws InternalError {
|
||||
/* asserts to help debugging */
|
||||
assert requestResponseCode != RequestResponseCode.LIST_RESPONSE || (this instanceof FileList) : "LIST_RESPONSE must use FilePart class";
|
||||
assert requestResponseCode != RequestResponseCode.LOAD_RESPONSE || (this instanceof FilePart) : "LOAD_RESPONSE must use FileList class";
|
||||
assert requestResponseCode != RequestResponseCode.LOAD_REQUEST || (this instanceof LoadRequest) : "LOAD_REQUEST must use LoadRequest class";
|
||||
assert requestResponseCode != RequestResponseCode.HASH_REQUEST || (this instanceof HashRequest) : "HASH_REQUEST must use HashRequest class";
|
||||
assert requestResponseCode != RequestResponseCode.HASH_RESPONSE || (this instanceof HashResponse) : "HASH_RESPONSE must use HashResponse class";
|
||||
assert requestResponseCode != RequestResponseCode.LIST_RESPONSE || (this instanceof FileList) : "LIST_RESPONSE must use FilePart class";
|
||||
assert requestResponseCode != RequestResponseCode.LOAD_RESPONSE || (this instanceof FilePart) : "LOAD_RESPONSE must use FileList class";
|
||||
assert requestResponseCode != RequestResponseCode.LOAD_REQUEST || (this instanceof LoadRequest) : "LOAD_REQUEST must use LoadRequest class";
|
||||
assert requestResponseCode != RequestResponseCode.HASH_REQUEST || (this instanceof HashRequest) : "HASH_REQUEST must use HashRequest class";
|
||||
assert requestResponseCode != RequestResponseCode.HASH_RESPONSE || (this instanceof HashResponse) : "HASH_RESPONSE must use HashResponse class";
|
||||
assert requestResponseCode != RequestResponseCode.DISCOVER_REQUEST || (this instanceof DiscoverRequest) : "DISCOVER_REQUEST must use DiscoverRequest class";
|
||||
assert requestResponseCode != RequestResponseCode.DISCOVER_RESPONSE || (this instanceof DiscoverResponse) : "DISCOVER_RESPONSE must use DiscoverResponse class";
|
||||
assert requestResponseCode != RequestResponseCode.REGISTER || (this instanceof Register) : "REGISTER must use Register class";
|
||||
assert requestResponseCode != RequestResponseCode.UNREGISTER || (this instanceof Unregister) : "UNREGISTER must use Unregister class";
|
||||
this.requestResponseCode = requestResponseCode;
|
||||
checkRequestResponseCode(); // this can throw InternalError
|
||||
}
|
||||
@ -46,13 +54,19 @@ public class Payload {
|
||||
*/
|
||||
protected Payload(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError {
|
||||
/* asserts to help debugging */
|
||||
assert getPayloadSize(packet) + 8 <= packet.length : "Payload is truncated";
|
||||
if (packet.length < getPayloadSize(packet) + 8) {
|
||||
assert getPayloadSize(packet) + PAYLOAD_START_POSITION <= packet.length : "Payload is truncated";
|
||||
if (packet.length < getPayloadSize(packet) + PAYLOAD_START_POSITION) {
|
||||
throw new TransmissionError();
|
||||
}
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LIST_RESPONSE || (this instanceof FileList) : "LIST_RESPONSE must use FilePart class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LOAD_RESPONSE || (this instanceof FilePart) : "LOAD_RESPONSE must use FileList class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LOAD_REQUEST || (this instanceof LoadRequest) : "LOAD_REQUEST must use LoadRequest class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LIST_RESPONSE || (this instanceof FileList) : "LIST_RESPONSE must use FilePart class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LOAD_RESPONSE || (this instanceof FilePart) : "LOAD_RESPONSE must use FileList class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LOAD_REQUEST || (this instanceof LoadRequest) : "LOAD_REQUEST must use LoadRequest class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.HASH_REQUEST || (this instanceof HashRequest) : "HASH_REQUEST must use HashRequest class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.HASH_RESPONSE || (this instanceof HashResponse) : "HASH_RESPONSE must use HashResponse class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.DISCOVER_REQUEST || (this instanceof DiscoverRequest) : "DISCOVER_REQUEST must use DiscoverRequest class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.DISCOVER_RESPONSE || (this instanceof DiscoverResponse) : "DISCOVER_RESPONSE must use DiscoverResponse class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.REGISTER || (this instanceof Register) : "REGISTER must use Register class";
|
||||
assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.UNREGISTER || (this instanceof Unregister) : "UNREGISTER must use Unregister class";
|
||||
requestResponseCode = RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]);
|
||||
checkRequestResponseCode(); // this can throw InternalError
|
||||
}
|
||||
@ -62,9 +76,16 @@ public class Payload {
|
||||
*/
|
||||
private void checkRequestResponseCode() throws InternalError {
|
||||
/* Incorrect use cases (use subclasses instead) */
|
||||
if ((requestResponseCode == RequestResponseCode.LIST_RESPONSE && !(this instanceof FileList))
|
||||
|| (requestResponseCode == RequestResponseCode.LOAD_RESPONSE && !(this instanceof FilePart))
|
||||
|| (requestResponseCode == RequestResponseCode.LOAD_REQUEST && !(this instanceof LoadRequest))) {
|
||||
if ((requestResponseCode == RequestResponseCode.LIST_RESPONSE && !(this instanceof FileList))
|
||||
|| (requestResponseCode == RequestResponseCode.LOAD_RESPONSE && !(this instanceof FilePart))
|
||||
|| (requestResponseCode == RequestResponseCode.LOAD_REQUEST && !(this instanceof LoadRequest))
|
||||
|| (requestResponseCode == RequestResponseCode.HASH_REQUEST && !(this instanceof HashRequest))
|
||||
|| (requestResponseCode == RequestResponseCode.HASH_RESPONSE && !(this instanceof HashResponse))
|
||||
|| (requestResponseCode == RequestResponseCode.DISCOVER_REQUEST && !(this instanceof DiscoverRequest))
|
||||
|| (requestResponseCode == RequestResponseCode.DISCOVER_RESPONSE && !(this instanceof DiscoverResponse))
|
||||
|| (requestResponseCode == RequestResponseCode.REGISTER && !(this instanceof Register))
|
||||
|| (requestResponseCode == RequestResponseCode.UNREGISTER && !(this instanceof Unregister))
|
||||
) {
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,9 @@ import remoteException.NotFound;
|
||||
import remoteException.ProtocolRemoteError;
|
||||
import remoteException.VersionRemoteError;
|
||||
import remoteException.EmptyFile;
|
||||
import java.net.InetAddress;
|
||||
import remoteException.NotATracker;
|
||||
import java.io.IOException;
|
||||
import tools.HostItem;
|
||||
|
||||
/** Representation of packet.
|
||||
* @author Louis Royer
|
||||
@ -50,9 +51,16 @@ public abstract class ProtocolP2PPacket {
|
||||
*/
|
||||
public abstract void sendResponse(ProtocolP2PPacket response) throws InternalError, IOException, SocketClosed;
|
||||
|
||||
/** Get hostItem of the sender
|
||||
* @return hostItem of the sender
|
||||
* @throws InternalError
|
||||
*/
|
||||
public abstract HostItem getHostItem() throws InternalError;
|
||||
|
||||
/** Receive a response
|
||||
* @throws EmptyFile
|
||||
* @throws NotFound
|
||||
* @throws NotATracker
|
||||
* @throws EmptyDirectory
|
||||
* @throws InternalRemoteError
|
||||
* @throws VersionRemoteError
|
||||
@ -65,7 +73,7 @@ public abstract class ProtocolP2PPacket {
|
||||
* @throws IOException
|
||||
* @throws SocketClosed
|
||||
*/
|
||||
public abstract ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException, SocketClosed;
|
||||
public abstract ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, NotATracker, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException, SocketClosed;
|
||||
|
||||
/** Receive a request, subclasses must overwrite this constructor.
|
||||
* @param socket socket used to get the request
|
||||
@ -101,6 +109,7 @@ public abstract class ProtocolP2PPacket {
|
||||
*/
|
||||
protected void checkProtocolVersion() throws VersionError {
|
||||
if (PROTOCOL_VERSION != version) {
|
||||
System.err.println("Error: wrong version in packet:" + version);
|
||||
throw new VersionError();
|
||||
}
|
||||
}
|
||||
|
@ -5,20 +5,19 @@ import localException.SizeError;
|
||||
import localException.TransmissionError;
|
||||
import localException.VersionError;
|
||||
import localException.SocketClosed;
|
||||
import remoteException.NotATracker;
|
||||
import remoteException.EmptyDirectory;
|
||||
import remoteException.InternalRemoteError;
|
||||
import remoteException.NotFound;
|
||||
import remoteException.ProtocolRemoteError;
|
||||
import remoteException.VersionRemoteError;
|
||||
import remoteException.EmptyFile;
|
||||
import tools.BytesArrayTools;
|
||||
import tools.HostItem;
|
||||
import protocolP2P.Payload;
|
||||
import protocolP2P.RequestResponseCode;
|
||||
import protocolP2P.LoadRequest;
|
||||
import protocolP2P.FileList;
|
||||
import protocolP2P.FilePart;
|
||||
import java.util.ArrayList;
|
||||
import java.lang.Byte;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
@ -67,9 +66,9 @@ public class ProtocolP2PPacketTCP extends ProtocolP2PPacket {
|
||||
socket.close();
|
||||
} catch (IOException e2) {
|
||||
System.err.println("Cannot close socket");
|
||||
} finally {
|
||||
throw new SocketClosed();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,14 +108,16 @@ public class ProtocolP2PPacketTCP extends ProtocolP2PPacket {
|
||||
Socket ss = (Socket)socket;
|
||||
byte[] packet = new byte[1024];
|
||||
try {
|
||||
System.err.println("Reading " + ss.getInputStream().read(packet) + " bytes");
|
||||
if (-1 == ss.getInputStream().read(packet)) {
|
||||
throw new IOException();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Error: cannot read request, closing socket
|
||||
try {
|
||||
ss.close();
|
||||
throw new SocketClosed();
|
||||
} catch (IOException e2) {
|
||||
System.err.println("Cannot close socket");
|
||||
} finally {
|
||||
throw new SocketClosed();
|
||||
}
|
||||
}
|
||||
@ -138,6 +139,8 @@ public class ProtocolP2PPacketTCP extends ProtocolP2PPacket {
|
||||
case LOAD_RESPONSE:
|
||||
case LIST_RESPONSE:
|
||||
case HASH_RESPONSE:
|
||||
case DISCOVER_RESPONSE:
|
||||
case NOT_A_TRACKER:
|
||||
// we were expecting a request, but we are receiving a response
|
||||
throw new ProtocolError();
|
||||
default :
|
||||
@ -188,6 +191,7 @@ public class ProtocolP2PPacketTCP extends ProtocolP2PPacket {
|
||||
* @return ProtocolP2PPacket received
|
||||
* @throws EmptyFile
|
||||
* @throws NotFound
|
||||
* @throws NotATracker
|
||||
* @throws EmptyDirectory
|
||||
* @throws InternalRemoteError
|
||||
* @throws VersionRemoteError
|
||||
@ -200,14 +204,27 @@ public class ProtocolP2PPacketTCP extends ProtocolP2PPacket {
|
||||
* @throws IOException
|
||||
* @throws SocketClosed
|
||||
*/
|
||||
public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException, SocketClosed {
|
||||
public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, NotATracker, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException, SocketClosed {
|
||||
assert requestSocket != null : "Cannot receive response because request packet not sent.";
|
||||
if (requestSocket == null) {
|
||||
throw new InternalError();
|
||||
}
|
||||
// reception
|
||||
byte[] packet = new byte[8192];
|
||||
requestSocket.getInputStream().read(packet);
|
||||
try {
|
||||
if (-1== requestSocket.getInputStream().read(packet)) {
|
||||
throw new IOException();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Error: cannot read request, closing socket
|
||||
try {
|
||||
requestSocket.close();
|
||||
throw new SocketClosed();
|
||||
} catch (IOException e2) {
|
||||
System.err.println("Cannot close socket");
|
||||
throw new SocketClosed();
|
||||
}
|
||||
}
|
||||
// contruction
|
||||
try {
|
||||
ProtocolP2PPacketTCP p = new ProtocolP2PPacketTCP(packet);
|
||||
@ -225,6 +242,8 @@ public class ProtocolP2PPacketTCP extends ProtocolP2PPacket {
|
||||
throw new NotFound();
|
||||
case EMPTY_FILE:
|
||||
throw new EmptyFile();
|
||||
case NOT_A_TRACKER:
|
||||
throw new NotATracker();
|
||||
default :
|
||||
return (ProtocolP2PPacket)p;
|
||||
}
|
||||
@ -288,6 +307,18 @@ public class ProtocolP2PPacketTCP extends ProtocolP2PPacket {
|
||||
case HASH_RESPONSE:
|
||||
payload = (Payload) new HashResponse(packet);
|
||||
break;
|
||||
case REGISTER:
|
||||
payload = (Payload) new Register(packet);
|
||||
break;
|
||||
case UNREGISTER:
|
||||
payload = (Payload) new Unregister(packet);
|
||||
break;
|
||||
case DISCOVER_REQUEST:
|
||||
payload = (Payload) new DiscoverRequest(packet);
|
||||
break;
|
||||
case DISCOVER_RESPONSE:
|
||||
payload = (Payload) new DiscoverResponse(packet);
|
||||
break;
|
||||
default:
|
||||
payload = new Payload(packet); // this can throw TransmissionError
|
||||
break;
|
||||
@ -319,4 +350,15 @@ public class ProtocolP2PPacketTCP extends ProtocolP2PPacket {
|
||||
return packet;
|
||||
}
|
||||
|
||||
/** Get hostItem of the sender
|
||||
* @return hostItem of the sender
|
||||
* @throws InternalError
|
||||
*/
|
||||
public HostItem getHostItem() throws InternalError {
|
||||
if (responseSocket == null) {
|
||||
throw new InternalError();
|
||||
}
|
||||
return new HostItem(responseSocket.getInetAddress().getHostName(), responseSocket.getPort());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import localException.SizeError;
|
||||
import localException.TransmissionError;
|
||||
import localException.VersionError;
|
||||
import localException.SocketClosed;
|
||||
import remoteException.NotATracker;
|
||||
import remoteException.EmptyDirectory;
|
||||
import remoteException.InternalRemoteError;
|
||||
import remoteException.NotFound;
|
||||
@ -12,13 +13,12 @@ import remoteException.ProtocolRemoteError;
|
||||
import remoteException.VersionRemoteError;
|
||||
import remoteException.EmptyFile;
|
||||
import tools.BytesArrayTools;
|
||||
import tools.HostItem;
|
||||
import protocolP2P.Payload;
|
||||
import protocolP2P.RequestResponseCode;
|
||||
import protocolP2P.LoadRequest;
|
||||
import protocolP2P.FileList;
|
||||
import protocolP2P.FilePart;
|
||||
import java.util.ArrayList;
|
||||
import java.lang.Byte;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.SocketAddress;
|
||||
@ -33,6 +33,7 @@ import java.io.IOException;
|
||||
public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
|
||||
private final static int CHECKSUM_POSITION = 2;
|
||||
private HostItem remoteHost;
|
||||
private SocketAddress responseSocketAddress; // socket address used when receptionning request and to sending response
|
||||
private DatagramSocket responseSocket; // socket used to recept request and send response
|
||||
private DatagramSocket requestSocket; // socket used to send request and to reception response
|
||||
@ -112,6 +113,7 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
DatagramPacket reception = new DatagramPacket(packet, packet.length);
|
||||
ss.receive(reception);
|
||||
responseSocketAddress = reception.getSocketAddress();
|
||||
remoteHost = new HostItem(reception.getAddress().getHostName(), reception.getPort());
|
||||
// contruction
|
||||
boolean protocolError = false;
|
||||
try {
|
||||
@ -130,6 +132,8 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
case LOAD_RESPONSE:
|
||||
case LIST_RESPONSE:
|
||||
case HASH_RESPONSE:
|
||||
case DISCOVER_RESPONSE:
|
||||
case NOT_A_TRACKER:
|
||||
// we were expecting a request, but we are receiving a response
|
||||
throw new ProtocolError();
|
||||
default :
|
||||
@ -183,6 +187,7 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
* @return ProtocolP2PPacket received
|
||||
* @throws EmptyFile
|
||||
* @throws NotFound
|
||||
* @throws NotATracker
|
||||
* @throws EmptyDirectory
|
||||
* @throws InternalRemoteError
|
||||
* @throws VersionRemoteError
|
||||
@ -194,7 +199,7 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
* @throws SizeError
|
||||
* @throws IOException
|
||||
*/
|
||||
public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {
|
||||
public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, NotATracker, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {
|
||||
assert requestSocket != null : "Cannot receive response because request packet not sent.";
|
||||
if (requestSocket == null) {
|
||||
throw new InternalError();
|
||||
@ -203,6 +208,7 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
byte[] packet = new byte[8192];
|
||||
DatagramPacket reception = new DatagramPacket(packet, packet.length);
|
||||
requestSocket.receive(reception);
|
||||
|
||||
// contruction
|
||||
try {
|
||||
ProtocolP2PPacketUDP p = new ProtocolP2PPacketUDP(packet);
|
||||
@ -220,6 +226,8 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
throw new NotFound();
|
||||
case EMPTY_FILE:
|
||||
throw new EmptyFile();
|
||||
case NOT_A_TRACKER:
|
||||
throw new NotATracker();
|
||||
default :
|
||||
return (ProtocolP2PPacket)p;
|
||||
}
|
||||
@ -284,6 +292,18 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
case HASH_RESPONSE:
|
||||
payload = (Payload) new HashResponse(packet);
|
||||
break;
|
||||
case REGISTER:
|
||||
payload = (Payload) new Register(packet);
|
||||
break;
|
||||
case UNREGISTER:
|
||||
payload = (Payload) new Unregister(packet);
|
||||
break;
|
||||
case DISCOVER_REQUEST:
|
||||
payload = (Payload) new DiscoverRequest(packet);
|
||||
break;
|
||||
case DISCOVER_RESPONSE:
|
||||
payload = (Payload) new DiscoverResponse(packet);
|
||||
break;
|
||||
default:
|
||||
payload = new Payload(packet); // this can throw TransmissionError
|
||||
break;
|
||||
@ -353,7 +373,6 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
* @param packet full packet
|
||||
* @throws TransmissionError
|
||||
*/
|
||||
|
||||
private void checkCheckSum(byte [] packet) throws TransmissionError {
|
||||
try {
|
||||
int checksum = BytesArrayTools.readInt16Bits(packet, CHECKSUM_POSITION);
|
||||
@ -365,4 +384,15 @@ public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
|
||||
throw new TransmissionError();
|
||||
}
|
||||
}
|
||||
|
||||
/** Get hostItem of the sender
|
||||
* @return hostItem of the sender
|
||||
* @throws InternalError
|
||||
*/
|
||||
public HostItem getHostItem() throws InternalError {
|
||||
if (remoteHost == null) {
|
||||
throw new InternalError();
|
||||
}
|
||||
return remoteHost;
|
||||
}
|
||||
}
|
||||
|
77
src/protocolP2P/Register.java
Normal file
77
src/protocolP2P/Register.java
Normal file
@ -0,0 +1,77 @@
|
||||
package protocolP2P;
|
||||
import protocolP2P.Payload;
|
||||
import tools.HostItem;
|
||||
import tools.BytesArrayTools;
|
||||
import localException.SizeError;
|
||||
import localException.InternalError;
|
||||
import localException.TransmissionError;
|
||||
import localException.ProtocolError;
|
||||
|
||||
/** Representation of payload for unregister.
|
||||
* @author Louis Royer
|
||||
* @author Flavien Haas
|
||||
* @author JS Auge
|
||||
* @version 1.0
|
||||
*/
|
||||
public class Register extends Payload {
|
||||
private HostItem hostItem;
|
||||
private static final int HOSTNAME_START_POSITION = PAYLOAD_START_POSITION + 2;
|
||||
|
||||
/** Constructor with hostItem (typically used by client)
|
||||
* @param hostItem Host you want to register.
|
||||
* @throws InternalError
|
||||
*/
|
||||
public Register(HostItem hostItem) throws InternalError {
|
||||
super(RequestResponseCode.REGISTER);
|
||||
this.hostItem = hostItem;
|
||||
}
|
||||
|
||||
/** Constructor (typically used by server) with a byte[] parameter containing the Packet received.
|
||||
* @param packet the full Packet received
|
||||
* @throws SizeError
|
||||
* @throws InternalError
|
||||
* @throws ProtocolError
|
||||
* @throws TransmissionError
|
||||
*/
|
||||
protected Register(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError {
|
||||
super(packet);
|
||||
int size = getPayloadSize(packet);
|
||||
int port = BytesArrayTools.readInt16Bits(packet, PAYLOAD_START_POSITION);
|
||||
String hostname = BytesArrayTools.readString(packet, HOSTNAME_START_POSITION, size - HOSTNAME_START_POSITION + PAYLOAD_START_POSITION);
|
||||
hostItem = new HostItem(hostname, port);
|
||||
}
|
||||
|
||||
/** Returns a byte[] containing Packet with padding.
|
||||
* This Packet is still incomplete and should not be send directly.
|
||||
* ProtocolP2PPacket will use this method to generate the complete Packet.
|
||||
* @return Packet with padding
|
||||
* @throws InternalError
|
||||
*/
|
||||
protected byte[] toPacket() throws InternalError {
|
||||
String hostname = hostItem.getHostname();
|
||||
// compute total size
|
||||
int size = HOSTNAME_START_POSITION + hostname.length();
|
||||
byte[] packet = new byte[size + 1]; // java initialize all to zero
|
||||
// set request/response code
|
||||
packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
|
||||
// set Payload size
|
||||
setPayloadSize(size - PAYLOAD_START_POSITION, packet);
|
||||
// write port to Packet
|
||||
try {
|
||||
BytesArrayTools.write16Bits(packet, PAYLOAD_START_POSITION, hostItem.getPort());
|
||||
} catch (SizeError e) {
|
||||
throw new InternalError();
|
||||
}
|
||||
// write hostname to Packet
|
||||
BytesArrayTools.write(packet, hostname, HOSTNAME_START_POSITION);
|
||||
return packet;
|
||||
}
|
||||
|
||||
/** HostItem getter.
|
||||
* @return hostItem
|
||||
*/
|
||||
public HostItem getHostItem() {
|
||||
return hostItem;
|
||||
}
|
||||
|
||||
}
|
@ -15,15 +15,20 @@ public enum RequestResponseCode {
|
||||
LIST_REQUEST(CodeType.REQUEST, (byte)0x00),
|
||||
LOAD_REQUEST(CodeType.REQUEST, (byte)0x01),
|
||||
HASH_REQUEST(CodeType.REQUEST, (byte)0x02),
|
||||
DISCOVER_REQUEST(CodeType.REQUEST_TRACKER, (byte)0x03),
|
||||
REGISTER(CodeType.REQUEST_TRACKER, (byte)0x04),
|
||||
UNREGISTER(CodeType.REQUEST_TRACKER, (byte)0x05),
|
||||
LIST_RESPONSE(CodeType.RESPONSE, (byte)0x80),
|
||||
LOAD_RESPONSE(CodeType.RESPONSE, (byte)0x81),
|
||||
HASH_RESPONSE(CodeType.RESPONSE, (byte)0x82),
|
||||
DISCOVER_RESPONSE(CodeType.RESPONSE, (byte)0x83),
|
||||
VERSION_ERROR(CodeType.ERROR, (byte)0xC0),
|
||||
PROTOCOL_ERROR(CodeType.ERROR, (byte)0xC1),
|
||||
INTERNAL_ERROR(CodeType.ERROR, (byte)0xC2),
|
||||
EMPTY_DIRECTORY(CodeType.ERROR, (byte)0xC3),
|
||||
NOT_FOUND(CodeType.ERROR, (byte)0xC4),
|
||||
EMPTY_FILE(CodeType.ERROR, (byte)0xC5);
|
||||
EMPTY_FILE(CodeType.ERROR, (byte)0xC5),
|
||||
NOT_A_TRACKER(CodeType.ERROR, (byte)0xC6);
|
||||
|
||||
public final CodeType codeType;
|
||||
public final byte codeValue;
|
||||
|
77
src/protocolP2P/Unregister.java
Normal file
77
src/protocolP2P/Unregister.java
Normal file
@ -0,0 +1,77 @@
|
||||
package protocolP2P;
|
||||
import protocolP2P.Payload;
|
||||
import tools.HostItem;
|
||||
import tools.BytesArrayTools;
|
||||
import localException.SizeError;
|
||||
import localException.InternalError;
|
||||
import localException.TransmissionError;
|
||||
import localException.ProtocolError;
|
||||
|
||||
/** Representation of payload for unregister.
|
||||
* @author Louis Royer
|
||||
* @author Flavien Haas
|
||||
* @author JS Auge
|
||||
* @version 1.0
|
||||
*/
|
||||
public class Unregister extends Payload {
|
||||
private HostItem hostItem;
|
||||
private static final int HOSTNAME_START_POSITION = PAYLOAD_START_POSITION + 2;
|
||||
|
||||
/** Constructor with hostItem (typically used by client)
|
||||
* @param hostItem Host you want to register.
|
||||
* @throws InternalError
|
||||
*/
|
||||
public Unregister(HostItem hostItem) throws InternalError {
|
||||
super(RequestResponseCode.UNREGISTER);
|
||||
this.hostItem = hostItem;
|
||||
}
|
||||
|
||||
/** Constructor (typically used by server) with a byte[] parameter containing the Packet received.
|
||||
* @param packet the full Packet received
|
||||
* @throws SizeError
|
||||
* @throws InternalError
|
||||
* @throws ProtocolError
|
||||
* @throws TransmissionError
|
||||
*/
|
||||
protected Unregister(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError {
|
||||
super(packet);
|
||||
int size = getPayloadSize(packet);
|
||||
int port = BytesArrayTools.readInt16Bits(packet, PAYLOAD_START_POSITION);
|
||||
String hostname = BytesArrayTools.readString(packet, HOSTNAME_START_POSITION, size - HOSTNAME_START_POSITION + PAYLOAD_START_POSITION);
|
||||
hostItem = new HostItem(hostname, port);
|
||||
}
|
||||
|
||||
/** Returns a byte[] containing Packet with padding.
|
||||
* This Packet is still incomplete and should not be send directly.
|
||||
* ProtocolP2PPacket will use this method to generate the complete Packet.
|
||||
* @return Packet with padding
|
||||
* @throws InternalError
|
||||
*/
|
||||
protected byte[] toPacket() throws InternalError {
|
||||
String hostname = hostItem.getHostname();
|
||||
// compute total size
|
||||
int size = HOSTNAME_START_POSITION + hostname.length();
|
||||
byte[] packet = new byte[size + 1]; // java initialize all to zero
|
||||
// set request/response code
|
||||
packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
|
||||
// set Payload size
|
||||
setPayloadSize(size - PAYLOAD_START_POSITION, packet);
|
||||
// write port to Packet
|
||||
try {
|
||||
BytesArrayTools.write16Bits(packet, PAYLOAD_START_POSITION, hostItem.getPort());
|
||||
} catch (SizeError e) {
|
||||
throw new InternalError();
|
||||
}
|
||||
// write hostname to Packet
|
||||
BytesArrayTools.write(packet, hostname, HOSTNAME_START_POSITION);
|
||||
return packet;
|
||||
}
|
||||
|
||||
/** HostItem getter.
|
||||
* @return hostItem
|
||||
*/
|
||||
public HostItem getHostItem() {
|
||||
return hostItem;
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,6 @@ package remoteException;
|
||||
|
||||
import exception.RemoteException;
|
||||
|
||||
public class EmptyDirectory extends exception.RemoteException {
|
||||
public class EmptyDirectory extends RemoteException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package remoteException;
|
||||
|
||||
import exception.RemoteException;
|
||||
|
||||
public class EmptyFile extends exception.RemoteException {
|
||||
public class EmptyFile extends RemoteException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package remoteException;
|
||||
|
||||
import exception.RemoteException;
|
||||
|
||||
public class InternalRemoteError extends exception.RemoteException {
|
||||
public class InternalRemoteError extends RemoteException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
7
src/remoteException/NotATracker.java
Normal file
7
src/remoteException/NotATracker.java
Normal file
@ -0,0 +1,7 @@
|
||||
package remoteException;
|
||||
|
||||
import exception.RemoteException;
|
||||
|
||||
public class NotATracker extends RemoteException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
@ -2,6 +2,6 @@ package remoteException;
|
||||
|
||||
import exception.RemoteException;
|
||||
|
||||
public class NotFound extends exception.RemoteException {
|
||||
public class NotFound extends RemoteException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package remoteException;
|
||||
|
||||
import exception.RemoteException;
|
||||
|
||||
public class ProtocolRemoteError extends exception.RemoteException {
|
||||
public class ProtocolRemoteError extends RemoteException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ package remoteException;
|
||||
|
||||
import exception.RemoteException;
|
||||
|
||||
public class VersionRemoteError extends exception.RemoteException {
|
||||
public class VersionRemoteError extends RemoteException {
|
||||
private static final long serialVersionUID = 12L;
|
||||
}
|
||||
|
@ -23,20 +23,17 @@ import localException.SizeError;
|
||||
import localException.TransmissionError;
|
||||
import localException.VersionError;
|
||||
import localException.SocketClosed;
|
||||
import remoteException.EmptyDirectory;
|
||||
import remoteException.InternalRemoteError;
|
||||
import remoteException.NotFound;
|
||||
import remoteException.ProtocolRemoteError;
|
||||
import remoteException.VersionRemoteError;
|
||||
import remoteException.EmptyFile;
|
||||
import java.util.Arrays;
|
||||
import tools.Logger;
|
||||
import tools.LogLevel;
|
||||
import tools.HostItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import protocolP2P.HashAlgorithm;
|
||||
import protocolP2P.HashRequest;
|
||||
import protocolP2P.HashResponse;
|
||||
import protocolP2P.Register;
|
||||
import protocolP2P.Unregister;
|
||||
|
||||
|
||||
/** Implementation of P2P-JAVA-PROJECT VERSION 1.0 protocol for TCP.
|
||||
@ -50,24 +47,29 @@ public class ServerManagementTCP implements Runnable {
|
||||
private String[] fileList;
|
||||
private Map<String, byte[]> sha512 = new HashMap<>();
|
||||
private String baseDirectory;
|
||||
private int TCPPort;
|
||||
private ServerSocket socket;
|
||||
private Logger logger;
|
||||
private HostItem tracker;
|
||||
private HostItem server;
|
||||
|
||||
/** Constructor for TCP implementation, with baseDirectory and TCPPort parameters.
|
||||
* @param baseDirectory the root directory where files are stored
|
||||
* @param hostName the server will bind on this address
|
||||
* @param TCPPort the server will listen on this port
|
||||
* @param logger Logger item
|
||||
* @param tracker Tracker
|
||||
*/
|
||||
public ServerManagementTCP(String baseDirectory, int TCPPort, Logger logger) {
|
||||
public ServerManagementTCP(String baseDirectory, String hostName, int port, Logger logger, HostItem tracker) {
|
||||
server = new HostItem(hostName, port);
|
||||
this.tracker = tracker;
|
||||
this.logger = logger;
|
||||
this.baseDirectory = baseDirectory;
|
||||
this.TCPPort = TCPPort;
|
||||
initFileList();
|
||||
initSha512();
|
||||
try {
|
||||
socket = new ServerSocket(TCPPort);
|
||||
socket = new ServerSocket(server.getPort(), 10, server.getInetAddress());
|
||||
} catch (SocketException e) {
|
||||
logger.writeTCP("Error: cannot listen on port " + TCPPort, LogLevel.Error);
|
||||
logger.writeTCP("Error: cannot listen on " + server, LogLevel.Error);
|
||||
System.exit(-1);
|
||||
} catch (IOException e) {
|
||||
logger.writeTCP("Error: cannot openning socket", LogLevel.Error);
|
||||
@ -79,6 +81,7 @@ public class ServerManagementTCP implements Runnable {
|
||||
*/
|
||||
public void run() {
|
||||
logger.writeTCP("Server sucessfully started", LogLevel.Info);
|
||||
(new Thread(new TrackerRegisterer())).start();
|
||||
do {
|
||||
try {
|
||||
Socket s = socket.accept();
|
||||
@ -93,14 +96,12 @@ public class ServerManagementTCP implements Runnable {
|
||||
/** Private runnable class allowing to serve one client.
|
||||
*/
|
||||
private class ClientHandler implements Runnable {
|
||||
private Socket s;
|
||||
private String addr;
|
||||
private HostItem addr;
|
||||
/** Constructor with a socket.
|
||||
* @param s Socket of this client
|
||||
*/
|
||||
public ClientHandler(Socket s) {
|
||||
this.s = s;
|
||||
this.addr = "[" +s.getInetAddress().getHostAddress() + "]:" + s.getPort() + " ";
|
||||
addr = new HostItem(s);
|
||||
}
|
||||
|
||||
/** Implementation of runnable. This method allow to serve one client.
|
||||
@ -108,11 +109,11 @@ public class ServerManagementTCP implements Runnable {
|
||||
public void run() {
|
||||
|
||||
boolean end = false;
|
||||
logger.writeTCP(addr + "New connection", LogLevel.Action);
|
||||
logger.writeTCP("[" + addr + "] New connection", LogLevel.Action);
|
||||
do {
|
||||
end = handleRequest();
|
||||
} while(!end);
|
||||
logger.writeTCP(addr + "End of connection", LogLevel.Action);
|
||||
logger.writeTCP("[" + addr + "] End of connection", LogLevel.Action);
|
||||
}
|
||||
|
||||
/** Respond to next request incomming on socket s.
|
||||
@ -121,7 +122,7 @@ public class ServerManagementTCP implements Runnable {
|
||||
*/
|
||||
private boolean handleRequest() {
|
||||
try {
|
||||
ProtocolP2PPacketTCP pd = new ProtocolP2PPacketTCP((Object)s);
|
||||
ProtocolP2PPacketTCP pd = new ProtocolP2PPacketTCP((Object)addr.getTCPSocket());
|
||||
Payload p = pd.getPayload();
|
||||
switch (p.getRequestResponseCode()) {
|
||||
case LOAD_REQUEST:
|
||||
@ -136,6 +137,18 @@ public class ServerManagementTCP implements Runnable {
|
||||
logger.writeTCP(addr + "HASH_REQUEST", LogLevel.Action);
|
||||
sendHashResponse(pd);
|
||||
break;
|
||||
case DISCOVER_REQUEST:
|
||||
logger.writeTCP(addr + "DISCOVER_REQUEST", LogLevel.Action);
|
||||
sendNotATracker(pd);
|
||||
break;
|
||||
case UNREGISTER:
|
||||
logger.writeTCP(addr + "UNREGISTER", LogLevel.Action);
|
||||
sendNotATracker(pd);
|
||||
break;
|
||||
case REGISTER:
|
||||
logger.writeTCP(addr + "REGISTER", LogLevel.Action);
|
||||
sendNotATracker(pd);
|
||||
break;
|
||||
default:
|
||||
logger.writeTCP(addr + "Received grabbage", LogLevel.Action);
|
||||
sendInternalError(pd);
|
||||
@ -198,7 +211,18 @@ public class ServerManagementTCP implements Runnable {
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Send a NotATracker error message.
|
||||
* @param pd ProtocolP2PPacketTCP to respond
|
||||
*/
|
||||
private void sendNotATracker(ProtocolP2PPacketTCP pd) {
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.NOT_A_TRACKER)));
|
||||
} catch (Exception e) {
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Send response to list request
|
||||
* @param pd Request received
|
||||
*/
|
||||
@ -309,4 +333,40 @@ public class ServerManagementTCP implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/** Private runnable class allowing to initialize tracker while initializing server. */
|
||||
private class TrackerRegisterer implements Runnable {
|
||||
|
||||
/** Runnable implementation */
|
||||
public void run() {
|
||||
try {
|
||||
registerTracker();
|
||||
} catch (Exception e) {
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
System.exit(-4);
|
||||
}
|
||||
}
|
||||
/** Register server on tracker
|
||||
* @throws InternalError
|
||||
* @throws IOException
|
||||
* @throws SocketClosed
|
||||
*/
|
||||
private void registerTracker() throws InternalError, IOException, SocketClosed {
|
||||
logger.writeTCP("Unregistering from tracker", LogLevel.Info);
|
||||
ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new Unregister(server));
|
||||
p.sendRequest((Object)tracker.getTCPSocket());
|
||||
// FIXME: this is a hack
|
||||
// ProtocolP2PPacketTCP reads 1024 bytes but if 2 request comes at the same time InputStream is cleared fully
|
||||
// and we keep waiting forever on the other side
|
||||
// a fix could be to read only the header first, and read the required size after
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {}
|
||||
logger.writeTCP("Registering into tracker", LogLevel.Info);
|
||||
p = (ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new Register(server));
|
||||
p.sendRequest((Object)tracker.getTCPSocket());
|
||||
logger.writeTCP("Registering completed", LogLevel.Debug);
|
||||
tracker.closeTCPSocket();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,12 +22,6 @@ import localException.SizeError;
|
||||
import localException.TransmissionError;
|
||||
import localException.VersionError;
|
||||
import localException.SocketClosed;
|
||||
import remoteException.EmptyDirectory;
|
||||
import remoteException.InternalRemoteError;
|
||||
import remoteException.NotFound;
|
||||
import remoteException.ProtocolRemoteError;
|
||||
import remoteException.VersionRemoteError;
|
||||
import remoteException.EmptyFile;
|
||||
import java.util.Arrays;
|
||||
import tools.Logger;
|
||||
import tools.LogLevel;
|
||||
@ -36,6 +30,10 @@ import java.util.Map;
|
||||
import protocolP2P.HashAlgorithm;
|
||||
import protocolP2P.HashRequest;
|
||||
import protocolP2P.HashResponse;
|
||||
import tools.HostItem;
|
||||
import protocolP2P.Register;
|
||||
import protocolP2P.Unregister;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/** Implementation of P2P-JAVA-PROJECT VERSION 1.0 protocol for UDP.
|
||||
* @author Louis Royer
|
||||
@ -48,24 +46,29 @@ public class ServerManagementUDP implements Runnable {
|
||||
private String[] fileList;
|
||||
private Map<String, byte[]> sha512 = new HashMap<>();
|
||||
private String baseDirectory;
|
||||
private int UDPPort;
|
||||
private DatagramSocket socket;
|
||||
private Logger logger;
|
||||
private HostItem tracker;
|
||||
private HostItem server;
|
||||
|
||||
/** Constructor for UDP implementation, with baseDirectory and UDPPort parameters.
|
||||
* @param baseDirectory the root directory where files are stored
|
||||
* @param UDPPort the server will listen on this port
|
||||
* @param hostName the server will bind on this address
|
||||
* @param port the server will listen on this port
|
||||
* @param logger Logger item
|
||||
* @param tracker Tracker
|
||||
*/
|
||||
public ServerManagementUDP(String baseDirectory, int UDPPort, Logger logger) {
|
||||
public ServerManagementUDP(String baseDirectory, String hostName, int port, Logger logger, HostItem tracker) {
|
||||
server = new HostItem(hostName, port);
|
||||
this.logger = logger;
|
||||
this.baseDirectory = baseDirectory;
|
||||
this.UDPPort = UDPPort;
|
||||
this.tracker = tracker;
|
||||
initFileList();
|
||||
initSha512();
|
||||
try {
|
||||
socket = new DatagramSocket(UDPPort);
|
||||
socket = new DatagramSocket(server.getPort(), server.getInetAddress());
|
||||
} catch (SocketException e) {
|
||||
logger.writeUDP("Error: cannot listen on port " + UDPPort, LogLevel.Error);
|
||||
logger.writeUDP("Error: cannot listen on " + server, LogLevel.Error);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
@ -74,21 +77,28 @@ public class ServerManagementUDP implements Runnable {
|
||||
*/
|
||||
public void run() {
|
||||
logger.writeUDP("Server sucessfully started", LogLevel.Info);
|
||||
(new Thread(new TrackerRegisterer())).start();
|
||||
while(true) {
|
||||
try {
|
||||
ProtocolP2PPacketUDP pd = new ProtocolP2PPacketUDP((Object)socket);
|
||||
Payload p = pd.getPayload();
|
||||
switch (p.getRequestResponseCode()) {
|
||||
case LOAD_REQUEST:
|
||||
LoadRequestManagement(logger, p, pd);
|
||||
loadRequestManagement(pd);
|
||||
break;
|
||||
case LIST_REQUEST:
|
||||
ListRequestManagement(logger, pd);
|
||||
listRequestManagement(pd);
|
||||
break;
|
||||
case HASH_REQUEST:
|
||||
logger.writeUDP("Received HASH_REQUEST", LogLevel.Action);
|
||||
sendHashResponse(pd);
|
||||
break;
|
||||
case DISCOVER_REQUEST:
|
||||
case UNREGISTER:
|
||||
case REGISTER:
|
||||
logger.writeUDP("Received Tracker request", LogLevel.Action);
|
||||
sendNotATracker(pd);
|
||||
break;
|
||||
default:
|
||||
sendInternalError(pd);
|
||||
}
|
||||
@ -148,7 +158,11 @@ public class ServerManagementUDP implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadRequestManagement(Logger logger, Payload p, ProtocolP2PPacketUDP pd){
|
||||
/** Respond to LOAD requests
|
||||
* @param pd ProtocolP2PPacketUDP
|
||||
*/
|
||||
public void loadRequestManagement(ProtocolP2PPacketUDP pd){
|
||||
Payload p = pd.getPayload();
|
||||
logger.writeUDP("Received LOAD_REQUEST", LogLevel.Action);
|
||||
assert p instanceof LoadRequest : "payload must be an instance of LoadRequest";
|
||||
if (!(p instanceof LoadRequest)) {
|
||||
@ -198,14 +212,17 @@ public class ServerManagementUDP implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
public void ListRequestManagement(Logger logger, ProtocolP2PPacketUDP pd){
|
||||
/** Respond to LIST requests
|
||||
* @param pd ProtocolP2PPacketUDP
|
||||
*/
|
||||
public void listRequestManagement(ProtocolP2PPacketUDP pd) {
|
||||
logger.writeUDP("Received LIST_REQUEST", LogLevel.Action);
|
||||
try {
|
||||
if (fileList.length == 0) {
|
||||
logger.writeUDP("Sending EMPTY_DIRECTORY", LogLevel.Action);
|
||||
logger.writeUDP("Sending EMPTY_DIRECTORY to host " + pd.getHostItem(), LogLevel.Action);
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.EMPTY_DIRECTORY)));
|
||||
} else {
|
||||
logger.writeUDP("Sending LIST_RESPONSE", LogLevel.Action);
|
||||
logger.writeUDP("Sending LIST_RESPONSE to host " + pd.getHostItem(), LogLevel.Action);
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)(new FileList(fileList))));
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
@ -213,6 +230,17 @@ public class ServerManagementUDP implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/** Send a NotATracker error message.
|
||||
* @param pd ProtocolP2PPacketUDP to respond
|
||||
*/
|
||||
private void sendNotATracker(ProtocolP2PPacketUDP pd) {
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.NOT_A_TRACKER)));
|
||||
} catch (Exception e) {
|
||||
logger.writeUDP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Send hash response to hash request
|
||||
* @param pd Request received
|
||||
*/
|
||||
@ -251,5 +279,33 @@ public class ServerManagementUDP implements Runnable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Private runnable class allowing to initialize tracker while initializing server. */
|
||||
private class TrackerRegisterer implements Runnable {
|
||||
|
||||
/** Runnable implementation */
|
||||
public void run() {
|
||||
try {
|
||||
registerTracker();
|
||||
} catch (Exception e) {
|
||||
logger.writeUDP(e, LogLevel.Error);
|
||||
System.exit(-4);
|
||||
}
|
||||
}
|
||||
/** Register server on tracker
|
||||
* @throws InternalError
|
||||
* @throws IOException
|
||||
* @throws SocketClosed
|
||||
*/
|
||||
private void registerTracker() throws InternalError, IOException, SocketClosed {
|
||||
logger.writeUDP("Unregistering from tracker", LogLevel.Info);
|
||||
ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new Unregister(server));
|
||||
p.sendRequest((Object)tracker.getUDPSocket());
|
||||
logger.writeUDP("Registering into tracker", LogLevel.Info);
|
||||
p = (ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new Register(server));
|
||||
p.sendRequest((Object)tracker.getUDPSocket());
|
||||
logger.writeUDP("Registering completed", LogLevel.Debug);
|
||||
tracker.closeUDPSocket();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ import serverP2P.ServerManagementUDP;
|
||||
import serverP2P.ServerManagementTCP;
|
||||
import tools.Directories;
|
||||
import tools.Logger;
|
||||
import tools.HostItem;
|
||||
import java.util.Scanner;
|
||||
|
||||
/** Server only implementation
|
||||
* First argument of main method is port listened by the server, and is mandatory.
|
||||
@ -16,33 +18,36 @@ public class ServerP2P {
|
||||
private Directories directories;
|
||||
static private final String subdir = "seeded/";
|
||||
private Logger logger;
|
||||
private HostItem tracker;
|
||||
|
||||
/** Constructor with portStr containing a port number.
|
||||
* @param portStr String containing port number of listening.
|
||||
*/
|
||||
public ServerP2P(String portStr) {
|
||||
public ServerP2P(String portStr, String trackerHostname, String trackerPortStr) {
|
||||
port = Integer.valueOf(Integer.parseInt(portStr));
|
||||
tracker = new HostItem(trackerHostname, Integer.valueOf(Integer.parseInt(trackerPortStr)));
|
||||
directories = new Directories("P2P_JAVA_PROJECT_SERVER_" + port);
|
||||
directories.createSubdir(subdir);
|
||||
logger = new Logger(directories.getDataHomeDirectory() + "server.log");
|
||||
System.out.println("Server will listen on port " + port + " and serve files from " + directories.getDataHomeDirectory() + subdir);
|
||||
directories.askOpenDataHomeDirectory(subdir);
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
directories.askOpenDataHomeDirectory(subdir, scanner);
|
||||
scanner.close();
|
||||
}
|
||||
|
||||
/** Main program entry point
|
||||
* first parameter is port number and is mandatory
|
||||
* to test, run with: java -ea serverP2P.ServerP2P -- <portNumber>
|
||||
* to test, run with: java -ea serverP2P.ServerP2P -- <portNumber> <TrackerHostname> <TrackerPort>
|
||||
* @param args parameters
|
||||
*/
|
||||
public static void main(String [] args) {
|
||||
|
||||
if (args[1].equals("help") || args[1].equals("-h") || args[1].equals("h")){
|
||||
System.out.println("usage : java -ea serveurP2P.ServeurP2P -- <serveurPORT> <trackerHOSTNAME> <trackerPORT>");
|
||||
}
|
||||
else{
|
||||
ServerP2P s = new ServerP2P(args[1]);
|
||||
ServerManagementUDP smudp = new ServerManagementUDP(s.directories.getDataHomeDirectory() + subdir, s.port, s.logger);
|
||||
ServerManagementTCP smtcp = new ServerManagementTCP(s.directories.getDataHomeDirectory() + subdir, s.port, s.logger);
|
||||
ServerP2P s = new ServerP2P(args[1], args[2], args[3]);
|
||||
ServerManagementUDP smudp = new ServerManagementUDP(s.directories.getDataHomeDirectory() + subdir, "localhost", s.port, s.logger, s.tracker);
|
||||
ServerManagementTCP smtcp = new ServerManagementTCP(s.directories.getDataHomeDirectory() + subdir, "localhost", s.port, s.logger, s.tracker);
|
||||
Thread tudp = new Thread(smudp);
|
||||
tudp.setName("server UDP P2P-JAVA-PROJECT");
|
||||
tudp.start();
|
||||
@ -51,5 +56,4 @@ public class ServerP2P {
|
||||
ttcp.start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -219,6 +219,39 @@ public class BytesArrayTools {
|
||||
}
|
||||
}
|
||||
|
||||
/** Read string from byte array
|
||||
* @param array Byte array to read
|
||||
* @param start start position in byte array
|
||||
* @param endStr End string delimiter
|
||||
* @return String read
|
||||
* @throws InternalError
|
||||
*/
|
||||
public static String readString(byte[] array, int start, String endStr) throws InternalError {
|
||||
boolean failed = false;
|
||||
try {
|
||||
int i = start;
|
||||
while(true) {
|
||||
int j = i;
|
||||
for(byte b: endStr.getBytes()) {
|
||||
if (b != array[j]) {
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if (failed) {
|
||||
i++;
|
||||
failed = false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return readString(array, start, i - start);
|
||||
} catch(IndexOutOfBoundsException e) {
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
|
||||
/** Write byte Array to byte Array.
|
||||
* @param dst Destination byte Array
|
||||
* @param src Source byte Array
|
||||
|
@ -70,6 +70,7 @@ public class Directories {
|
||||
}
|
||||
|
||||
/** Opens dataHomeDirectory if supported.
|
||||
* @param subdir Subdir to open (optional)
|
||||
*/
|
||||
private void openDataHomeDirectory(String subdir) {
|
||||
String d = dataHomeDirectory;
|
||||
@ -93,11 +94,12 @@ public class Directories {
|
||||
}
|
||||
|
||||
/** Asks the user to choose opening dataHomeDirectory or not.
|
||||
* @param subdir subdirectory to open (optional)
|
||||
* @param scanner Scanner to use for reading input
|
||||
*/
|
||||
public void askOpenDataHomeDirectory(String subdir) {
|
||||
public void askOpenDataHomeDirectory(String subdir, Scanner scanner) {
|
||||
if (os.equals("Linux") || os.equals("Mac") || os.equals("Mac OS X")) {
|
||||
System.out.println("Do you want to open this directory? (y/N)");
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
String resp = scanner.nextLine();
|
||||
if (resp.equals("y") || resp.equals("Y")) {
|
||||
System.out.println("Openning");
|
||||
|
@ -17,6 +17,7 @@ public class HostItem {
|
||||
private int port;
|
||||
private Socket tcpSocket;
|
||||
private DatagramSocket udpSocket;
|
||||
private InetAddress inetAddress;
|
||||
|
||||
/** Constructor with hostname and port
|
||||
* @param hostname Hostname
|
||||
@ -35,13 +36,13 @@ public class HostItem {
|
||||
try {
|
||||
tcpSocket = new Socket(InetAddress.getByName(hostname), port);
|
||||
} catch (SocketException e) {
|
||||
System.err.println("Error: No TCP socket available.");
|
||||
System.err.println("getTCPSocket error: No TCP socket available.");
|
||||
System.exit(-1);
|
||||
} catch (UnknownHostException e) {
|
||||
System.err.println("Error: Unknown host.");
|
||||
System.err.println("getTCPSocket error: Unknown host (" + this + ").");
|
||||
System.exit(-1);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error: Cannot create TCP socket");
|
||||
System.err.println("getTCPSocket error: Cannot create TCP socket (" + this + ").");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
@ -70,19 +71,86 @@ public class HostItem {
|
||||
udpSocket = new DatagramSocket();
|
||||
udpSocket.connect(InetAddress.getByName(hostname), port);
|
||||
} catch (SocketException e) {
|
||||
System.err.println("Error: No UDP socket available.");
|
||||
System.err.println("getUDPSocket error: No UDP socket available." );
|
||||
System.exit(-1);
|
||||
} catch (UnknownHostException e) {
|
||||
System.err.println("Error: Unknown host.");
|
||||
System.err.println("getUDPSocket error: Unknown host (" + this + ").");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
return udpSocket;
|
||||
}
|
||||
|
||||
/** Closes udp socket
|
||||
*/
|
||||
public void closeUDPSocket() {
|
||||
if (udpSocket != null) {
|
||||
udpSocket.close();
|
||||
}
|
||||
udpSocket = null;
|
||||
}
|
||||
|
||||
/** Getter for hostname */
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
/** Getter for port */
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/** To string
|
||||
* @return String representation
|
||||
*/
|
||||
public String toString() {
|
||||
return getHostname() + " (port " + getPort() + ")";
|
||||
}
|
||||
|
||||
/** Override of equals method
|
||||
* @param other Object to test equality with
|
||||
* @return true if equals
|
||||
*/
|
||||
public boolean equals(Object other) {
|
||||
boolean result = false;
|
||||
if (other instanceof HostItem) {
|
||||
HostItem that = (HostItem) other;
|
||||
result = this.getHostname() == that.getHostname() && this.getPort() == that.getPort();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Override of hashCode method
|
||||
* @return a hash code for this object.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return hostname.hashCode() ^ port;
|
||||
}
|
||||
|
||||
/** Get InetAddress associated to this HostItem.
|
||||
* @return InetAddress
|
||||
*/
|
||||
public InetAddress getInetAddress() {
|
||||
if (inetAddress == null) {
|
||||
try {
|
||||
inetAddress = InetAddress.getByName(getHostname());
|
||||
} catch (UnknownHostException e) {
|
||||
System.err.println("getInetAddress error: Unknown host (" + this + ").");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
return inetAddress;
|
||||
}
|
||||
|
||||
/** Constructor from Socket.
|
||||
* @param s socket
|
||||
*/
|
||||
public HostItem(Socket s) {
|
||||
tcpSocket = s;
|
||||
inetAddress = s.getInetAddress();
|
||||
hostname = inetAddress.getCanonicalHostName();
|
||||
port = s.getPort();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
package tools;
|
||||
|
||||
import java.util.Scanner;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.InputMismatchException;
|
||||
import tools.HostItem;
|
||||
|
||||
/** Helper to get the server list from the user
|
||||
* @author Louis Royer
|
||||
* @author Flavien Haas
|
||||
* @author JS Auge
|
||||
* @version 1.0
|
||||
*/
|
||||
public class HostList {
|
||||
/**
|
||||
* Let the user enter all server and puts it in a list
|
||||
* @return list of servers
|
||||
*/
|
||||
public static List<HostItem> getServList() {
|
||||
List<HostItem> serverList = new ArrayList<HostItem>();
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
String servName;
|
||||
int port = 0;
|
||||
do {
|
||||
System.out.println("Enter hostname of next server: (or \"stop\" when finished, default: localhost).");
|
||||
servName = scanner.nextLine();
|
||||
if (servName.equals("")) {
|
||||
servName = "localhost";
|
||||
}
|
||||
if (!servName.equals("stop")) {
|
||||
boolean err = false;
|
||||
do {
|
||||
System.out.println("Enter port for this server");
|
||||
try {
|
||||
port = scanner.nextInt();
|
||||
scanner.nextLine();
|
||||
if (port > 65535 || port <= 0) {
|
||||
err = true;
|
||||
System.out.println("Port number must be in 1-65535 range. Try again.");
|
||||
} else {
|
||||
err = false;
|
||||
}
|
||||
} catch (InputMismatchException e) {
|
||||
System.out.println("Invalid number. Try again.");
|
||||
err = true;
|
||||
}
|
||||
} while (err);
|
||||
serverList.add(new HostItem(servName, port));
|
||||
}
|
||||
|
||||
} while (!servName.equals("stop"));
|
||||
return serverList;
|
||||
}
|
||||
}
|
@ -17,6 +17,9 @@ import java.sql.Timestamp;
|
||||
public class Logger {
|
||||
private Path logFile;
|
||||
|
||||
/** Constructor with logFile.
|
||||
* @param logFile name of the file to store logs.
|
||||
*/
|
||||
public Logger(String logFile) {
|
||||
assert logFile != null : "Logfile name is null";
|
||||
this.logFile = Paths.get(logFile);
|
||||
@ -120,4 +123,5 @@ public class Logger {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
50
src/tracker/Tracker.java
Normal file
50
src/tracker/Tracker.java
Normal file
@ -0,0 +1,50 @@
|
||||
package tracker;
|
||||
import tracker.TrackerManagementTCP;
|
||||
import tracker.TrackerManagementUDP;
|
||||
import tools.Directories;
|
||||
import tools.Logger;
|
||||
import java.util.Scanner;
|
||||
|
||||
/** Tracker implementation
|
||||
* First argument of main method is port listened by the tracker, and is mandatory.
|
||||
* @author Louis Royer
|
||||
* @author Flavien Haas
|
||||
* @author JS Auge
|
||||
* @version 1.0
|
||||
*/
|
||||
public class Tracker {
|
||||
private int port;
|
||||
private Directories directories;
|
||||
private Logger logger;
|
||||
|
||||
/** Constructor with portStr containing a port number.
|
||||
* @param portStr String containing port number of listening.
|
||||
*/
|
||||
public Tracker(String portStr) {
|
||||
port = Integer.valueOf(Integer.parseInt(portStr));
|
||||
directories = new Directories("P2P_JAVA_PROJECT_TRACKER_" + port);
|
||||
logger = new Logger(directories.getDataHomeDirectory() + "tracker.log");
|
||||
System.out.println("Tracker will listen on port " + port + " and write logs into " + directories.getDataHomeDirectory());
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
directories.askOpenDataHomeDirectory(null, scanner);
|
||||
scanner.close();
|
||||
}
|
||||
|
||||
/** Main program entry point
|
||||
* first parameter is port number and is mandatory
|
||||
* to test, run with: java -ea serverP2P.ServerP2P -- <portNumber>
|
||||
* @param args parameters
|
||||
*/
|
||||
public static void main(String [] args) {
|
||||
Tracker t = new Tracker(args[1]);
|
||||
TrackerManagementUDP tmudp = new TrackerManagementUDP(t.port, t.logger);
|
||||
TrackerManagementTCP tmtcp = new TrackerManagementTCP(t.port, t.logger);
|
||||
Thread tudp = new Thread(tmudp);
|
||||
tudp.setName("Tracker UDP P2P-JAVA-PROJECT");
|
||||
tudp.start();
|
||||
Thread ttcp = new Thread(tmtcp);
|
||||
ttcp.setName("Tracker TCP P2P-JAVA-PROJECT");
|
||||
ttcp.start();
|
||||
}
|
||||
|
||||
}
|
287
src/tracker/TrackerManagementTCP.java
Normal file
287
src/tracker/TrackerManagementTCP.java
Normal file
@ -0,0 +1,287 @@
|
||||
package tracker;
|
||||
import tools.Logger;
|
||||
import tools.LogLevel;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import protocolP2P.ProtocolP2PPacketTCP;
|
||||
import protocolP2P.ProtocolP2PPacket;
|
||||
import protocolP2P.RequestResponseCode;
|
||||
import protocolP2P.Payload;
|
||||
import protocolP2P.Register;
|
||||
import protocolP2P.Unregister;
|
||||
import tools.HostItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import exception.LocalException;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import protocolP2P.DiscoverRequest;
|
||||
import protocolP2P.DiscoverResponse;
|
||||
import protocolP2P.FileList;
|
||||
import localException.InternalError;
|
||||
import remoteException.EmptyDirectory;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.InetAddress;
|
||||
import localException.SocketClosed;
|
||||
|
||||
|
||||
/** Tracker management implementation with tcp
|
||||
* @author Louis Royer
|
||||
* @author Flavien Haas
|
||||
* @author JS Auge
|
||||
* @version 1.0
|
||||
*/
|
||||
public class TrackerManagementTCP implements Runnable {
|
||||
|
||||
private HostItem tracker;
|
||||
private Logger logger;
|
||||
private ServerSocket socket;
|
||||
private List<HostItem> hostList = new ArrayList<>();
|
||||
private Map<String, List<HostItem>> fileList = new HashMap<>();
|
||||
|
||||
/** Constructor with port and logger.
|
||||
* @param port Port used to listen.
|
||||
* @param logger Logger object
|
||||
*/
|
||||
public TrackerManagementTCP(int port, Logger logger) {
|
||||
tracker = new HostItem("localhost", port);
|
||||
this.logger = logger;
|
||||
try {
|
||||
socket = new ServerSocket(tracker.getPort(), 10, tracker.getInetAddress());
|
||||
} catch (SocketException e) {
|
||||
logger.writeTCP("Error: cannot listen on" + tracker, LogLevel.Error);
|
||||
System.exit(-1);
|
||||
} catch (IOException e) {
|
||||
logger.writeTCP("Error: cannot open socket", LogLevel.Error);
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of runnable. This methods allows to run the server.
|
||||
*/
|
||||
public void run() {
|
||||
logger.writeTCP("Tracker sucessfully started", LogLevel.Info);
|
||||
do {
|
||||
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);
|
||||
}
|
||||
} while(true);
|
||||
}
|
||||
|
||||
|
||||
/** Private runnable class allowing to serve one client.
|
||||
*/
|
||||
private class ClientHandler implements Runnable {
|
||||
private HostItem addr;
|
||||
/** Constructor with a socket.
|
||||
* @param s Socket of this client
|
||||
*/
|
||||
public ClientHandler(Socket s) {
|
||||
this.addr = new HostItem(s);
|
||||
}
|
||||
|
||||
/** Implementation of runnable. This method allow to serve one client.
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
boolean end = false;
|
||||
logger.writeTCP("[ " + addr + "] New connection", LogLevel.Action);
|
||||
do {
|
||||
end = handleRequest();
|
||||
} while(!end);
|
||||
logger.writeTCP("[ " + addr + "] End of connection", LogLevel.Action);
|
||||
}
|
||||
|
||||
/** Respond to next request incomming on socket s.
|
||||
* @param s Socket used to read request and send response
|
||||
* @return true if cannot expect another request (ie, socket is closed)
|
||||
*/
|
||||
private boolean handleRequest() {
|
||||
try {
|
||||
ProtocolP2PPacketTCP pd = new ProtocolP2PPacketTCP((Object)addr.getTCPSocket());
|
||||
Payload p = pd.getPayload();
|
||||
switch (p.getRequestResponseCode()) {
|
||||
case LOAD_REQUEST:
|
||||
logger.writeTCP("Received LOAD_REQUEST from host " + pd.getHostItem() + ", sending NOT_FOUND", LogLevel.Action);
|
||||
sendNotFound(pd);
|
||||
break;
|
||||
case LIST_REQUEST:
|
||||
logger.writeTCP("Received LIST_REQUEST from host " + pd.getHostItem() + ", sending EMPTY_DIRECTORY", LogLevel.Action);
|
||||
sendEmptyDirectory(pd);
|
||||
break;
|
||||
case HASH_REQUEST:
|
||||
logger.writeTCP("Received HASH_REQUEST from host " + pd.getHostItem() + ", sending NOT_FOUND", LogLevel.Action);
|
||||
sendNotFound(pd);
|
||||
break;
|
||||
case REGISTER:
|
||||
logger.writeTCP("Received REGISTER from host " + pd.getHostItem(), LogLevel.Debug);
|
||||
handleRegister(pd);
|
||||
break;
|
||||
case UNREGISTER:
|
||||
logger.writeTCP("Received UNREGISTER from host " + pd.getHostItem(), LogLevel.Debug);
|
||||
handleUnregister(pd);
|
||||
break;
|
||||
case DISCOVER_REQUEST:
|
||||
handleDiscover(pd);
|
||||
break;
|
||||
default:
|
||||
logger.writeTCP("Received grabbage from host " + pd.getHostItem(), LogLevel.Action);
|
||||
sendInternalError(pd);
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.writeTCP(e, LogLevel.Warning);
|
||||
return true;
|
||||
} catch (SocketClosed e) {
|
||||
return true;
|
||||
} catch (LocalException e) {
|
||||
logger.writeTCP(e, LogLevel.Warning);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Send a not found message.
|
||||
* @param pd ProtocolP2PPacketTCP to respond
|
||||
*/
|
||||
private void sendNotFound(ProtocolP2PPacketTCP pd) {
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.NOT_FOUND)));
|
||||
} catch (Exception e) {
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Send an empty directory message.
|
||||
* @param pd ProtocolP2PPacketTCP to respond
|
||||
*/
|
||||
private void sendEmptyDirectory(ProtocolP2PPacketTCP pd) {
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.EMPTY_DIRECTORY)));
|
||||
} catch (Exception e) {
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Send an internal error message.
|
||||
* @param pd ProtocolP2PPacketTCP to respond
|
||||
*/
|
||||
private void sendInternalError(ProtocolP2PPacketTCP pd) {
|
||||
logger.writeTCP("Internal Error", LogLevel.Warning);
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.INTERNAL_ERROR)));
|
||||
} catch (Exception e) {
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Registering
|
||||
* @param pd ProtocolP2PPacketTCP to respond
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void handleRegister(ProtocolP2PPacketTCP pd) throws InternalError {
|
||||
Payload p = pd.getPayload();
|
||||
assert p instanceof Register : "payload must be an instance of Register";
|
||||
if (!(p instanceof Register)) {
|
||||
throw new InternalError();
|
||||
}
|
||||
// add host to known host list
|
||||
HostItem host = ((Register)p).getHostItem();
|
||||
if (!hostList.contains(host)) {
|
||||
hostList.add(host);
|
||||
}
|
||||
// send a list request
|
||||
try {
|
||||
ProtocolP2PPacket pLReq = (ProtocolP2PPacket) new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.LIST_REQUEST));
|
||||
pLReq.sendRequest((Object)host.getTCPSocket());
|
||||
logger.writeTCP("Received REGISTER from host " + pd.getHostItem() + ". Adding host " + host + " to list. Sending List request", LogLevel.Action);
|
||||
handleListResponse((ProtocolP2PPacketTCP)pLReq.receiveResponse(), host);
|
||||
logger.writeTCP("Received LIST RESPONSE from host " + pd.getHostItem(), LogLevel.Action);
|
||||
host.closeTCPSocket();
|
||||
} catch (EmptyDirectory e) {
|
||||
logger.writeTCP("Empty Directory", LogLevel.Debug);
|
||||
hostList.remove(host);
|
||||
logger.writeTCP("Received EMPTY DIRECTORY from host " + pd.getHostItem() + ". Aborting.", LogLevel.Action);
|
||||
} catch (Exception e) {
|
||||
// remove from list because list request could not be send
|
||||
hostList.remove(host);
|
||||
logger.writeTCP("Aborting the add of host " + host, LogLevel.Action);
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Unregistering
|
||||
* @param pd ProtocolP2PPacketTCP to respond
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void handleUnregister(ProtocolP2PPacketTCP pd) throws InternalError {
|
||||
Payload p = pd.getPayload();
|
||||
assert p instanceof Unregister : "payload must be an instance of Unregister";
|
||||
if (!(p instanceof Unregister)) {
|
||||
sendInternalError(pd);
|
||||
throw new InternalError();
|
||||
}
|
||||
HostItem host = ((Unregister)p).getHostItem();
|
||||
logger.writeTCP("Received UNREGISTER from host " + pd.getHostItem() + ". Removing host " + host, LogLevel.Action);
|
||||
hostList.remove(host);
|
||||
for(String f: fileList.keySet()) {
|
||||
fileList.get(f).remove(host);
|
||||
if(fileList.get(f).isEmpty()) {
|
||||
fileList.remove(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Discover request
|
||||
* @param pd ProtocolP2PPacketTCP to respond
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void handleDiscover(ProtocolP2PPacketTCP pd) throws InternalError {
|
||||
logger.writeTCP("Received DISCOVER REQUEST from host " + pd.getHostItem(), LogLevel.Action);
|
||||
Payload p = pd.getPayload();
|
||||
assert p instanceof DiscoverRequest : "payload must be an instance of DiscoverRequest";
|
||||
if (!(p instanceof DiscoverRequest)) {
|
||||
sendInternalError(pd);
|
||||
} else {
|
||||
String filename = ((DiscoverRequest)p).getFilename();
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new DiscoverResponse(filename, fileList.getOrDefault(filename, hostList))));
|
||||
} catch (Exception e) {
|
||||
logger.writeTCP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle List Responses
|
||||
* @param pd ProtocolP2PPacketTCP response
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void handleListResponse(ProtocolP2PPacketTCP pd, HostItem host) throws InternalError {
|
||||
Payload p = pd.getPayload();
|
||||
assert p instanceof FileList: "payload must be an instance of FileList";
|
||||
if (!(p instanceof FileList)) {
|
||||
throw new InternalError();
|
||||
} else {
|
||||
String[] f = ((FileList)p).getFileList();
|
||||
for (String file: f) {
|
||||
List<HostItem> h = fileList.get(file);
|
||||
if (h != null) {
|
||||
if (!h.contains(host)) {
|
||||
h.add(host);
|
||||
}
|
||||
} else {
|
||||
List<HostItem> emptyH = new ArrayList<>();
|
||||
emptyH.add(host);
|
||||
fileList.put(file, emptyH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
237
src/tracker/TrackerManagementUDP.java
Normal file
237
src/tracker/TrackerManagementUDP.java
Normal file
@ -0,0 +1,237 @@
|
||||
package tracker;
|
||||
import tools.Logger;
|
||||
import tools.LogLevel;
|
||||
import java.net.DatagramSocket;
|
||||
import protocolP2P.ProtocolP2PPacketUDP;
|
||||
import protocolP2P.ProtocolP2PPacket;
|
||||
import protocolP2P.RequestResponseCode;
|
||||
import protocolP2P.Payload;
|
||||
import protocolP2P.Register;
|
||||
import protocolP2P.Unregister;
|
||||
import tools.HostItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
import exception.LocalException;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import protocolP2P.DiscoverRequest;
|
||||
import protocolP2P.DiscoverResponse;
|
||||
import protocolP2P.FileList;
|
||||
import localException.InternalError;
|
||||
import remoteException.EmptyDirectory;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/** Tracker management implementation with udp
|
||||
* @author Louis Royer
|
||||
* @author Flavien Haas
|
||||
* @author JS Auge
|
||||
* @version 1.0
|
||||
*/
|
||||
public class TrackerManagementUDP implements Runnable {
|
||||
|
||||
private HostItem tracker;
|
||||
private Logger logger;
|
||||
private DatagramSocket socket;
|
||||
private List<HostItem> hostList = new ArrayList<>();
|
||||
private Map<String, List<HostItem>> fileList = new HashMap<>();
|
||||
|
||||
/** Constructor with port and logger.
|
||||
* @param port Port used to listen.
|
||||
* @param logger Logger object
|
||||
*/
|
||||
public TrackerManagementUDP(int port, Logger logger) {
|
||||
tracker = new HostItem("localhost", port);
|
||||
this.logger = logger;
|
||||
try {
|
||||
socket = new DatagramSocket(tracker.getPort(), tracker.getInetAddress());
|
||||
} catch (SocketException e) {
|
||||
logger.writeUDP("Error: cannot listen on port " + port, LogLevel.Error);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of runnable. This methods allows to run the tracker.
|
||||
*/
|
||||
public void run() {
|
||||
logger.writeUDP("Tracker successfully started", LogLevel.Info);
|
||||
while(true) {
|
||||
try {
|
||||
ProtocolP2PPacketUDP pd = new ProtocolP2PPacketUDP((Object)socket);
|
||||
Payload p = pd.getPayload();
|
||||
switch (p.getRequestResponseCode()) {
|
||||
case LOAD_REQUEST:
|
||||
logger.writeUDP("Received LOAD_REQUEST from host " + pd.getHostItem() + ", sending NOT_FOUND", LogLevel.Action);
|
||||
sendNotFound(pd);
|
||||
break;
|
||||
case LIST_REQUEST:
|
||||
logger.writeUDP("Received LIST_REQUEST from host " + pd.getHostItem() + ", sending EMPTY_DIRECTORY", LogLevel.Action);
|
||||
sendEmptyDirectory(pd);
|
||||
break;
|
||||
case HASH_REQUEST:
|
||||
logger.writeUDP("Received HASH_REQUEST from host " + pd.getHostItem() + ", sending NOT_FOUND", LogLevel.Action);
|
||||
sendNotFound(pd);
|
||||
break;
|
||||
case REGISTER:
|
||||
handleRegister(pd);
|
||||
break;
|
||||
case UNREGISTER:
|
||||
handleUnregister(pd);
|
||||
break;
|
||||
case DISCOVER_REQUEST:
|
||||
handleDiscover(pd);
|
||||
break;
|
||||
default:
|
||||
logger.writeUDP("Received grabbage from host " + pd.getHostItem(), LogLevel.Action);
|
||||
sendInternalError(pd);
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.writeUDP(e, LogLevel.Warning);
|
||||
} catch (LocalException e) {
|
||||
logger.writeUDP(e, LogLevel.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Send a not found message.
|
||||
* @param pd ProtocolP2PPacketUDP to respond
|
||||
*/
|
||||
private void sendNotFound(ProtocolP2PPacketUDP pd) {
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.NOT_FOUND)));
|
||||
} catch (Exception e) {
|
||||
logger.writeUDP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Send an empty directory message.
|
||||
* @param pd ProtocolP2PPacketUDP to respond
|
||||
*/
|
||||
private void sendEmptyDirectory(ProtocolP2PPacketUDP pd) {
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.EMPTY_DIRECTORY)));
|
||||
} catch (Exception e) {
|
||||
logger.writeUDP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Send an internal error message.
|
||||
* @param pd ProtocolP2PPacketUDP to respond
|
||||
*/
|
||||
private void sendInternalError(ProtocolP2PPacketUDP pd) {
|
||||
logger.writeUDP("Internal Error", LogLevel.Warning);
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.INTERNAL_ERROR)));
|
||||
} catch (Exception e) {
|
||||
logger.writeUDP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Registering
|
||||
* @param pd ProtocolP2PPacketUDP to respond
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void handleRegister(ProtocolP2PPacketUDP pd) throws InternalError {
|
||||
Payload p = pd.getPayload();
|
||||
assert p instanceof Register : "payload must be an instance of Register";
|
||||
if (!(p instanceof Register)) {
|
||||
sendInternalError(pd);
|
||||
throw new InternalError();
|
||||
}
|
||||
// add host to known host list
|
||||
HostItem host = ((Register)p).getHostItem();
|
||||
if (!hostList.contains(host)) {
|
||||
hostList.add(host);
|
||||
}
|
||||
// send a list request
|
||||
try {
|
||||
ProtocolP2PPacket pLReq = (ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.LIST_REQUEST));
|
||||
pLReq.sendRequest((Object)host.getUDPSocket());
|
||||
logger.writeUDP("Received REGISTER from host " + pd.getHostItem() + ". Adding host " + host + " to list. Sending List request", LogLevel.Action);
|
||||
ProtocolP2PPacket resp = pLReq.receiveResponse();
|
||||
handleListResponse((ProtocolP2PPacketUDP)resp, host);
|
||||
logger.writeUDP("Received LIST RESPONSE from host " + pd.getHostItem(), LogLevel.Action);
|
||||
host.closeUDPSocket();
|
||||
} catch (EmptyDirectory e) {
|
||||
logger.writeUDP("Empty Directory", LogLevel.Debug);
|
||||
hostList.remove(host);
|
||||
logger.writeUDP("Received EMPTY DIRECTORY from host " + pd.getHostItem() + ". Aborting.", LogLevel.Action);
|
||||
} catch (Exception e) {
|
||||
// remove from list because list request could not be send
|
||||
hostList.remove(host);
|
||||
logger.writeUDP("Aborting the add of host " + host, LogLevel.Action);
|
||||
logger.writeUDP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Unregistering
|
||||
* @param pd ProtocolP2PPacketUDP to respond
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void handleUnregister(ProtocolP2PPacketUDP pd) throws InternalError {
|
||||
Payload p = pd.getPayload();
|
||||
assert p instanceof Unregister : "payload must be an instance of Unregister";
|
||||
if (!(p instanceof Unregister)) {
|
||||
sendInternalError(pd);
|
||||
throw new InternalError();
|
||||
}
|
||||
HostItem host = ((Unregister)p).getHostItem();
|
||||
logger.writeUDP("Received UNREGISTER from host " + pd.getHostItem() + ". Removing host " + host, LogLevel.Action);
|
||||
hostList.remove(host);
|
||||
for(String f: fileList.keySet()) {
|
||||
fileList.get(f).remove(host);
|
||||
if(fileList.get(f).isEmpty()) {
|
||||
fileList.remove(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Discover request
|
||||
* @param pd ProtocolP2PPacketUDP to respond
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void handleDiscover(ProtocolP2PPacketUDP pd) throws InternalError {
|
||||
logger.writeUDP("Received DISCOVER REQUEST from host " + pd.getHostItem(), LogLevel.Action);
|
||||
Payload p = pd.getPayload();
|
||||
assert p instanceof DiscoverRequest : "payload must be an instance of DiscoverRequest";
|
||||
if (!(p instanceof DiscoverRequest)) {
|
||||
sendInternalError(pd);
|
||||
} else {
|
||||
String filename = ((DiscoverRequest)p).getFilename();
|
||||
try {
|
||||
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new DiscoverResponse(filename, fileList.getOrDefault(filename, hostList))));
|
||||
} catch (Exception e) {
|
||||
logger.writeUDP(e, LogLevel.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle List Responses
|
||||
* @param pd ProtocolP2PPacketUDP response
|
||||
* @throws InternalError
|
||||
*/
|
||||
private void handleListResponse(ProtocolP2PPacketUDP pd, HostItem host) throws InternalError {
|
||||
Payload p = pd.getPayload();
|
||||
assert p instanceof FileList: "payload must be an instance of FileList";
|
||||
if (!(p instanceof FileList)) {
|
||||
throw new InternalError();
|
||||
} else {
|
||||
String[] f = ((FileList)p).getFileList();
|
||||
for (String file: f) {
|
||||
List<HostItem> h = fileList.get(file);
|
||||
if (h != null) {
|
||||
if (!h.contains(host)) {
|
||||
h.add(host);
|
||||
}
|
||||
} else {
|
||||
List<HostItem> emptyH = new ArrayList<>();
|
||||
emptyH.add(host);
|
||||
fileList.put(file, emptyH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user