Fix #27
- [x] Faire un thread qui tous les X secondes (configurable) va comparer les fichiers dispo avec la liste et mettre à jour (penser à le logger). La mise à jour peut s’effectuer en faisant juste une REGISTER REQUEST.
This commit is contained in:
parent
0253f38b4d
commit
0c10752e9b
@ -1,5 +1,5 @@
|
|||||||
package exception;
|
package exception;
|
||||||
|
|
||||||
public class LocalException extends Exception {
|
public abstract class LocalException extends Exception {
|
||||||
private static final long serialVersionUID = 12L;
|
private static final long serialVersionUID = 12L;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package exception;
|
package exception;
|
||||||
|
|
||||||
public class RemoteException extends Exception {
|
public abstract class RemoteException extends Exception {
|
||||||
private static final long serialVersionUID = 12L;
|
private static final long serialVersionUID = 12L;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,8 @@ public class ServerManagementTCP implements Runnable {
|
|||||||
private Logger logger;
|
private Logger logger;
|
||||||
private HostItem tracker;
|
private HostItem tracker;
|
||||||
private HostItem server;
|
private HostItem server;
|
||||||
|
private FileListWatcher fileListWatcher;
|
||||||
|
private volatile boolean stop;
|
||||||
|
|
||||||
/** Constructor for TCP implementation, with baseDirectory and TCPPort parameters.
|
/** Constructor for TCP implementation, with baseDirectory and TCPPort parameters.
|
||||||
* @param baseDirectory the root directory where files are stored
|
* @param baseDirectory the root directory where files are stored
|
||||||
@ -60,12 +62,12 @@ public class ServerManagementTCP implements Runnable {
|
|||||||
* @param tracker Tracker
|
* @param tracker Tracker
|
||||||
*/
|
*/
|
||||||
public ServerManagementTCP(String baseDirectory, String hostName, int port, Logger logger, HostItem tracker) {
|
public ServerManagementTCP(String baseDirectory, String hostName, int port, Logger logger, HostItem tracker) {
|
||||||
|
stop = false;
|
||||||
server = new HostItem(hostName, port);
|
server = new HostItem(hostName, port);
|
||||||
|
fileList = new String[0];
|
||||||
this.tracker = tracker;
|
this.tracker = tracker;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.baseDirectory = baseDirectory;
|
this.baseDirectory = baseDirectory;
|
||||||
initFileList();
|
|
||||||
initSha512();
|
|
||||||
try {
|
try {
|
||||||
socket = new ServerSocket(server.getPort(), 10, server.getInetAddress());
|
socket = new ServerSocket(server.getPort(), 10, server.getInetAddress());
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
@ -77,12 +79,26 @@ public class ServerManagementTCP implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Stop the thread */
|
||||||
|
public void setStop() {
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Trigger a manual check of the file list
|
||||||
|
*/
|
||||||
|
public void updateFileList() {
|
||||||
|
if (fileListWatcher != null) {
|
||||||
|
fileListWatcher.trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Implementation of runnable. This methods allows to run the server.
|
/** Implementation of runnable. This methods allows to run the server.
|
||||||
*/
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.writeTCP("Server sucessfully started", LogLevel.Info);
|
logger.writeTCP("Server sucessfully started", LogLevel.Info);
|
||||||
(new Thread(new TrackerRegisterer())).start();
|
fileListWatcher = new FileListWatcher(10000); // checking every 10 seconds
|
||||||
do {
|
(new Thread(fileListWatcher)).start();
|
||||||
|
while(!stop) {
|
||||||
try {
|
try {
|
||||||
Socket s = socket.accept();
|
Socket s = socket.accept();
|
||||||
ClientHandler c = new ClientHandler(s);
|
ClientHandler c = new ClientHandler(s);
|
||||||
@ -90,7 +106,17 @@ public class ServerManagementTCP implements Runnable {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.writeTCP("Error while accepting new connection", LogLevel.Warning);
|
logger.writeTCP("Error while accepting new connection", LogLevel.Warning);
|
||||||
}
|
}
|
||||||
} while(true);
|
}
|
||||||
|
fileListWatcher.setStop();
|
||||||
|
// unregistering from tracker
|
||||||
|
try {
|
||||||
|
logger.writeTCP("Unregistering from tracker", LogLevel.Info);
|
||||||
|
ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new Unregister(server));
|
||||||
|
p.sendRequest((Object)tracker.getTCPSocket());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.writeTCP("Cannot unregister from tracker", LogLevel.Error);
|
||||||
|
logger.writeTCP(e, LogLevel.Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Private runnable class allowing to serve one client.
|
/** Private runnable class allowing to serve one client.
|
||||||
@ -167,22 +193,6 @@ public class ServerManagementTCP implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initialize local list of all files allowed to be shared.
|
|
||||||
*/
|
|
||||||
private void initFileList() {
|
|
||||||
File folder = new File(baseDirectory);
|
|
||||||
Vector<String> v = new Vector<String>();
|
|
||||||
File[] files = folder.listFiles();
|
|
||||||
/* Add non-recursively files's names to fileList */
|
|
||||||
for (File f : files) {
|
|
||||||
if (f.isFile()) {
|
|
||||||
v.add(f.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fileList = new String[v.size()];
|
|
||||||
v.toArray(fileList);
|
|
||||||
Arrays.sort(fileList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Init sha512 map.
|
/** Init sha512 map.
|
||||||
*/
|
*/
|
||||||
@ -333,40 +343,90 @@ public class ServerManagementTCP implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Private runnable class allowing to initialize tracker while initializing server. */
|
/** Private runnable class allowing to keep the tracker informed about file list. */
|
||||||
private class TrackerRegisterer implements Runnable {
|
private class FileListWatcher implements Runnable {
|
||||||
|
private volatile boolean stop;
|
||||||
|
private long time;
|
||||||
|
private boolean force;
|
||||||
|
|
||||||
|
/** Register server on tracker
|
||||||
|
*/
|
||||||
|
private void registerTracker() {
|
||||||
|
try {
|
||||||
|
logger.writeTCP("Trying to into tracker", LogLevel.Info);
|
||||||
|
ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new Register(server));
|
||||||
|
p.sendRequest((Object)tracker.tryGetTCPSocket());
|
||||||
|
logger.writeTCP("Register request sent.", LogLevel.Debug);
|
||||||
|
tracker.closeTCPSocket();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// error, trying again at next iteration
|
||||||
|
force = true;
|
||||||
|
logger.writeTCP("Cannot contact tracker, trying again at next iteration (" + time + " milliseconds).", LogLevel.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update fileList and returns true if different than old list.
|
||||||
|
* @return true if changed
|
||||||
|
*/
|
||||||
|
private boolean updateFileList() {
|
||||||
|
File folder = new File(baseDirectory);
|
||||||
|
Vector<String> v = new Vector<String>();
|
||||||
|
File[] files = folder.listFiles();
|
||||||
|
/* Add non-recursively files's names to fileList */
|
||||||
|
for (File f : files) {
|
||||||
|
if (f.isFile()) {
|
||||||
|
v.add(f.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String[] newFileList = new String[v.size()];
|
||||||
|
v.toArray(newFileList);
|
||||||
|
Arrays.sort(newFileList);
|
||||||
|
if (!Arrays.equals(newFileList, fileList)) {
|
||||||
|
fileList = newFileList;
|
||||||
|
initSha512();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructor with millis parameter
|
||||||
|
* @param millis interval of time between checks
|
||||||
|
*/
|
||||||
|
public FileListWatcher(long millis) {
|
||||||
|
this.stop = false;
|
||||||
|
this.time = millis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ask the thread to stop
|
||||||
|
*/
|
||||||
|
public void setStop() {
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Allow a manual check
|
||||||
|
*/
|
||||||
|
public void trigger() {
|
||||||
|
if (updateFileList() || force) {
|
||||||
|
force = false;
|
||||||
|
logger.writeTCP("File list watcher detected changes. Informing tracker.", LogLevel.Info);
|
||||||
|
registerTracker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Runnable implementation */
|
/** Runnable implementation */
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
logger.writeTCP("File list watcher started : delay " + time + " milliseconds.", LogLevel.Info);
|
||||||
registerTracker();
|
while(!stop) {
|
||||||
} catch (Exception e) {
|
trigger();
|
||||||
logger.writeTCP(e, LogLevel.Error);
|
try {
|
||||||
System.exit(-4);
|
Thread.sleep(time);
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
logger.writeTCP("File list watcher interrupted", LogLevel.Error);
|
||||||
|
setStop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,13 +43,15 @@ import java.net.UnknownHostException;
|
|||||||
*/
|
*/
|
||||||
public class ServerManagementUDP implements Runnable {
|
public class ServerManagementUDP implements Runnable {
|
||||||
|
|
||||||
private String[] fileList;
|
private String[] fileList = new String[0];
|
||||||
private Map<String, byte[]> sha512 = new HashMap<>();
|
private Map<String, byte[]> sha512 = new HashMap<>();
|
||||||
private String baseDirectory;
|
private String baseDirectory;
|
||||||
private DatagramSocket socket;
|
private DatagramSocket socket;
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
private HostItem tracker;
|
private HostItem tracker;
|
||||||
private HostItem server;
|
private HostItem server;
|
||||||
|
private FileListWatcher fileListWatcher;
|
||||||
|
private volatile boolean stop;
|
||||||
|
|
||||||
/** Constructor for UDP implementation, with baseDirectory and UDPPort parameters.
|
/** Constructor for UDP implementation, with baseDirectory and UDPPort parameters.
|
||||||
* @param baseDirectory the root directory where files are stored
|
* @param baseDirectory the root directory where files are stored
|
||||||
@ -59,12 +61,11 @@ public class ServerManagementUDP implements Runnable {
|
|||||||
* @param tracker Tracker
|
* @param tracker Tracker
|
||||||
*/
|
*/
|
||||||
public ServerManagementUDP(String baseDirectory, String hostName, int port, Logger logger, HostItem tracker) {
|
public ServerManagementUDP(String baseDirectory, String hostName, int port, Logger logger, HostItem tracker) {
|
||||||
|
stop = false;
|
||||||
server = new HostItem(hostName, port);
|
server = new HostItem(hostName, port);
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.baseDirectory = baseDirectory;
|
this.baseDirectory = baseDirectory;
|
||||||
this.tracker = tracker;
|
this.tracker = tracker;
|
||||||
initFileList();
|
|
||||||
initSha512();
|
|
||||||
try {
|
try {
|
||||||
socket = new DatagramSocket(server.getPort(), server.getInetAddress());
|
socket = new DatagramSocket(server.getPort(), server.getInetAddress());
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
@ -73,12 +74,26 @@ public class ServerManagementUDP implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Stop the thread */
|
||||||
|
public void setStop() {
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Trigger a manual check of the file list
|
||||||
|
*/
|
||||||
|
public void updateFileList() {
|
||||||
|
if (fileListWatcher != null) {
|
||||||
|
fileListWatcher.trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Implementation of runnable. This methods allows to run the server.
|
/** Implementation of runnable. This methods allows to run the server.
|
||||||
*/
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.writeUDP("Server sucessfully started", LogLevel.Info);
|
logger.writeUDP("Server sucessfully started", LogLevel.Info);
|
||||||
(new Thread(new TrackerRegisterer())).start();
|
fileListWatcher = new FileListWatcher(10000); // checking every 10 seconds
|
||||||
while(true) {
|
(new Thread(fileListWatcher)).start();
|
||||||
|
while(!stop) {
|
||||||
try {
|
try {
|
||||||
ProtocolP2PPacketUDP pd = new ProtocolP2PPacketUDP((Object)socket);
|
ProtocolP2PPacketUDP pd = new ProtocolP2PPacketUDP((Object)socket);
|
||||||
Payload p = pd.getPayload();
|
Payload p = pd.getPayload();
|
||||||
@ -111,23 +126,15 @@ public class ServerManagementUDP implements Runnable {
|
|||||||
} catch (SizeError e) {
|
} catch (SizeError e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
fileListWatcher.setStop();
|
||||||
|
// unregistering from tracker
|
||||||
/** Initialize local list of all files allowed to be shared.
|
try {
|
||||||
*/
|
logger.writeUDP("Unregistering from tracker", LogLevel.Info);
|
||||||
private void initFileList() {
|
ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new Unregister(server));
|
||||||
File folder = new File(baseDirectory);
|
p.sendRequest((Object)tracker.getUDPSocket());
|
||||||
Vector<String> v = new Vector<String>();
|
} catch (Exception e) {
|
||||||
File[] files = folder.listFiles();
|
logger.writeUDP(e, LogLevel.Error);
|
||||||
/* Add non-recursively files's names to fileList */
|
|
||||||
for (File f : files) {
|
|
||||||
if (f.isFile()) {
|
|
||||||
v.add(f.getName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fileList = new String[v.size()];
|
|
||||||
v.toArray(fileList);
|
|
||||||
Arrays.sort(fileList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Init sha512 map.
|
/** Init sha512 map.
|
||||||
@ -280,32 +287,89 @@ public class ServerManagementUDP implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Private runnable class allowing to initialize tracker while initializing server. */
|
/** Private runnable class allowing to keep the tracker informed about file list. */
|
||||||
private class TrackerRegisterer implements Runnable {
|
private class FileListWatcher implements Runnable {
|
||||||
|
private volatile boolean stop;
|
||||||
|
private long time;
|
||||||
|
private boolean force;
|
||||||
|
|
||||||
|
/** Register server on tracker
|
||||||
|
*/
|
||||||
|
private void registerTracker() {
|
||||||
|
try {
|
||||||
|
logger.writeUDP("Trying to register into tracker", LogLevel.Info);
|
||||||
|
ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new Register(server));
|
||||||
|
p.sendRequest((Object)tracker.getUDPSocket());
|
||||||
|
logger.writeUDP("Register request sent (but cannot ensure reception).", LogLevel.Debug);
|
||||||
|
tracker.closeUDPSocket();
|
||||||
|
} catch (Exception e) {
|
||||||
|
force = true;
|
||||||
|
logger.writeUDP("Cannot contact tracker, trying again at next iteration (" + time + " milliseconds).", LogLevel.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update fileList and returns true if different than old list.
|
||||||
|
* @return true if changed
|
||||||
|
*/
|
||||||
|
private boolean updateFileList() {
|
||||||
|
File folder = new File(baseDirectory);
|
||||||
|
Vector<String> v = new Vector<String>();
|
||||||
|
File[] files = folder.listFiles();
|
||||||
|
/* Add non-recursively files's names to fileList */
|
||||||
|
for (File f : files) {
|
||||||
|
if (f.isFile()) {
|
||||||
|
v.add(f.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String[] newFileList = new String[v.size()];
|
||||||
|
v.toArray(newFileList);
|
||||||
|
Arrays.sort(newFileList);
|
||||||
|
if (!Arrays.equals(newFileList, fileList)) {
|
||||||
|
fileList = newFileList;
|
||||||
|
initSha512();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructor with millis parameter
|
||||||
|
* @param millis interval of time between checks
|
||||||
|
*/
|
||||||
|
public FileListWatcher(long millis) {
|
||||||
|
this.force = true;
|
||||||
|
this.stop = false;
|
||||||
|
this.time = millis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ask the thread to stop
|
||||||
|
*/
|
||||||
|
public void setStop() {
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Allow a manual check
|
||||||
|
*/
|
||||||
|
public void trigger() {
|
||||||
|
if (updateFileList() || force) {
|
||||||
|
force = false;
|
||||||
|
logger.writeUDP("File list watcher detected changes. Informing tracker.", LogLevel.Info);
|
||||||
|
registerTracker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Runnable implementation */
|
/** Runnable implementation */
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
logger.writeUDP("File list watcher started : delay " + time + " milliseconds.", LogLevel.Info);
|
||||||
registerTracker();
|
while(!stop) {
|
||||||
} catch (Exception e) {
|
trigger();
|
||||||
logger.writeUDP(e, LogLevel.Error);
|
try {
|
||||||
System.exit(-4);
|
Thread.sleep(time);
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
logger.writeUDP("File list watcher interrupted", LogLevel.Error);
|
||||||
|
setStop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,19 @@ public class HostItem {
|
|||||||
return tcpSocket;
|
return tcpSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get TCP Socket.
|
||||||
|
* @return TCP Socket
|
||||||
|
* @throws SocketException
|
||||||
|
* @throws UnknownHostException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public Socket tryGetTCPSocket() throws SocketException, UnknownHostException, IOException {
|
||||||
|
if (tcpSocket == null) {
|
||||||
|
tcpSocket = new Socket(InetAddress.getByName(hostname), port);
|
||||||
|
}
|
||||||
|
return tcpSocket;
|
||||||
|
}
|
||||||
|
|
||||||
/** Closes tcp socket
|
/** Closes tcp socket
|
||||||
*/
|
*/
|
||||||
public void closeTCPSocket() {
|
public void closeTCPSocket() {
|
||||||
|
@ -75,9 +75,11 @@ public class TrackerManagementUDP implements Runnable {
|
|||||||
sendNotFound(pd);
|
sendNotFound(pd);
|
||||||
break;
|
break;
|
||||||
case REGISTER:
|
case REGISTER:
|
||||||
|
logger.writeUDP("Received REGISTER from host " + pd.getHostItem(), LogLevel.Debug);
|
||||||
handleRegister(pd);
|
handleRegister(pd);
|
||||||
break;
|
break;
|
||||||
case UNREGISTER:
|
case UNREGISTER:
|
||||||
|
logger.writeUDP("Received UNREGISTER from host " + pd.getHostItem(), LogLevel.Debug);
|
||||||
handleUnregister(pd);
|
handleUnregister(pd);
|
||||||
break;
|
break;
|
||||||
case DISCOVER_REQUEST:
|
case DISCOVER_REQUEST:
|
||||||
|
Loading…
Reference in New Issue
Block a user