240 lines
7.8 KiB
Java
240 lines
7.8 KiB
Java
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:
|
|
logger.writeUDP("Received REGISTER from host " + pd.getHostItem(), LogLevel.Debug);
|
|
handleRegister(pd);
|
|
break;
|
|
case UNREGISTER:
|
|
logger.writeUDP("Received UNREGISTER from host " + pd.getHostItem(), LogLevel.Debug);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|