Merge remote-tracking branch 'origin/master'

This commit is contained in:
Arnaud Vergnet 2020-12-01 10:30:58 +01:00
commit f4f32cc0bc
2 changed files with 139 additions and 42 deletions

View file

@ -1,84 +1,184 @@
package fr.insa.clavardator.network; package fr.insa.clavardator.network;
import fr.insa.clavardator.users.ActiveUser;
import fr.insa.clavardator.util.ErrorHandler; import fr.insa.clavardator.util.ErrorHandler;
import java.io.IOException; import java.io.IOException;
import java.net.DatagramPacket; import java.net.*;
import java.net.DatagramSocket; import java.util.ArrayList;
import java.net.InetAddress; import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
public class NetDiscoverer { public class NetDiscoverer {
private static final short DISCOVERY_PORT = 31596; private static final short DISCOVERY_PORT = 31593;
private static final short RESPONSE_PORT = 31597; private static final short RESPONSE_PORT = 31594;
public static final int BROADCAST_BUFFER_SIZE = 50;
public static final int RESPONSE_BUFFER_SIZE = 50;
public NetDiscoverer() {} private NetDiscoverer() {
}
/** /**
* @param message * Discovers all active users in the network, and call the callback for each of them
* @param callback *
* @param callback function to call when a new user is discovered
*/ */
public void sendBroadcast(String message, NetDiscoverer.ResponseReceivedCallback callback) { public static void discoverActiveUsers(ResponseReceivedCallback callback) {
NetDiscoverer.BroadcastSender sender = new NetDiscoverer.BroadcastSender(message, callback); ResponseListener receiver = new ResponseListener(callback);
BroadcastSender sender = new BroadcastSender("USER_DISCOVERY_BROADCAST");
receiver.start();
sender.start();
}
/**
* Starts to listen for discovery broadcasts and answers them
*/
public static void startDiscoveryListening() {
BroadcastListener listener = new BroadcastListener(
(ipAddr, data) -> new ResponseSender(ipAddr, "USER_DISCOVERY_RESPONSE").start()
);
listener.start();
} }
private static class BroadcastSender extends Thread { private static class BroadcastSender extends Thread {
String broadcastMessage; String broadcastMessage;
NetDiscoverer.ResponseReceivedCallback callback;
/** /**
* Constructs and starts a thread that sends a broadcast over the network * Constructs and starts a thread that sends a broadcast over the network
*
* @param broadcastMessage The message to send * @param broadcastMessage The message to send
* @param callback The function to call once finished
*/ */
public BroadcastSender(String broadcastMessage, NetDiscoverer.ResponseReceivedCallback callback) { public BroadcastSender(String broadcastMessage) {
this.broadcastMessage = broadcastMessage; this.broadcastMessage = broadcastMessage;
this.callback = callback;
start();
} }
@Override @Override
public void run() { public void run() {
byte[] buf = broadcastMessage.getBytes(); byte[] buf = broadcastMessage.getBytes();
try { try {
DatagramSocket broadcastSocket = new DatagramSocket(DISCOVERY_PORT); for (InetAddress broadcastAddr : listAllBroadcastAddresses()) {
broadcastSocket.setBroadcast(true); DatagramSocket broadcastSocket = new DatagramSocket();
broadcastSocket.bind(null); broadcastSocket.setBroadcast(true);
broadcastSocket.send(new DatagramPacket(buf, buf.length)); broadcastSocket.send(new DatagramPacket(buf, buf.length, broadcastAddr, DISCOVERY_PORT));
// System.out.println("Broadcast sent with address " + broadcastAddr.toString());
}
} catch (IOException e) { } catch (IOException e) {
ErrorHandler.getInstance().notifyError(e); ErrorHandler.getInstance().notifyError(e);
} }
} }
} }
private static class Listener extends Thread { private static class BroadcastListener extends Thread {
final short port; BroadcastReceivedCallback callback;
public BroadcastListener(BroadcastReceivedCallback callback) {
public Listener(short port) { this.callback = callback;
this.port = port;
} }
@Override @Override
public void run() { public void run() {
//TODO while (true) { // TODO: add a stop condition
try {
DatagramSocket listener = new DatagramSocket(null);
listener.setOption(StandardSocketOptions.SO_REUSEPORT, true);
listener.setOption(StandardSocketOptions.SO_REUSEADDR, true);
listener.bind(new InetSocketAddress((InetAddress) null, DISCOVERY_PORT));
byte[] buffer = new byte[BROADCAST_BUFFER_SIZE];
DatagramPacket receivedPacket = new DatagramPacket(buffer, BROADCAST_BUFFER_SIZE);
listener.receive(receivedPacket);
// System.out.println("broadcast received from " + receivedPacket.getAddress().toString());
callback.onBroadcastReceived(receivedPacket.getAddress(), new String(receivedPacket.getData()));
} catch (IOException e) {
e.printStackTrace();
ErrorHandler.getInstance().notifyError(e);
}
}
}
}
private static class ResponseSender extends Thread {
String message;
InetAddress address;
/**
* Constructs and starts a thread that sends a broadcast over the network
*
* @param message The message to send
*/
public ResponseSender(InetAddress address, String message) {
this.address = address;
this.message = message;
}
@Override
public void run() {
byte[] buf = message.getBytes();
try {
DatagramSocket responseSocket = new DatagramSocket();
responseSocket.send(new DatagramPacket(buf, buf.length, address, RESPONSE_PORT));
// System.out.println("Response sent to " + address.toString());
} catch (IOException e) {
ErrorHandler.getInstance().notifyError(e);
}
}
}
private static class ResponseListener extends Thread {
ResponseReceivedCallback callback;
public ResponseListener(ResponseReceivedCallback callback) {
this.callback = callback;
}
@Override
public void run() {
while (true) { // TODO: add a stop condition
try {
DatagramSocket listener = new DatagramSocket(null);
listener.setOption(StandardSocketOptions.SO_REUSEPORT, true);
listener.setOption(StandardSocketOptions.SO_REUSEADDR, true);
listener.bind(new InetSocketAddress((InetAddress) null, RESPONSE_PORT));
byte[] buffer = new byte[RESPONSE_BUFFER_SIZE];
DatagramPacket receivedPacket = new DatagramPacket(buffer, RESPONSE_BUFFER_SIZE);
listener.receive(receivedPacket);
// System.out.println("response received from " + receivedPacket.getAddress().toString());
callback.onResponseReceived(receivedPacket.getAddress(), new String(receivedPacket.getData()));
} catch (IOException e) {
ErrorHandler.getInstance().notifyError(e);
}
}
} }
} }
static List<InetAddress> listAllBroadcastAddresses() throws SocketException {
List<InetAddress> broadcastList = new ArrayList<>();
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
if (!networkInterface.isLoopback() && networkInterface.isUp()) {
networkInterface.getInterfaceAddresses().stream()
.map(InterfaceAddress::getBroadcast)
.filter(Objects::nonNull)
.forEach(broadcastList::add);
}
}
return broadcastList;
}
public interface ResponseReceivedCallback { public interface ResponseReceivedCallback {
void onActiverUserDiscovered(ActiveUser user); void onResponseReceived(InetAddress ipAddr, String data);
}
private interface ResponseSentCallback {
void onResponseSent();
} }
private interface BroadcastReceivedCallback { private interface BroadcastReceivedCallback {
void onBroadcastReceived(InetAddress ipAddr); void onBroadcastReceived(InetAddress ipAddr, String data);
}
private interface BroadcastSentCallback {
void onBroadcastSent();
} }
} }

View file

@ -12,7 +12,6 @@ public class UserList {
private ArrayList<ActiveUser> activeUsers; private ArrayList<ActiveUser> activeUsers;
private ArrayList<PeerUser> inactiveUsers; private ArrayList<PeerUser> inactiveUsers;
private final NetDiscoverer netDiscoverer = new NetDiscoverer();
private final DatabaseController db = new DatabaseController(); private final DatabaseController db = new DatabaseController();
// Make this class observable // Make this class observable
@ -49,12 +48,10 @@ public class UserList {
* *
*/ */
public void discoverActiveUsers() { public void discoverActiveUsers() {
netDiscoverer.sendBroadcast("", new NetDiscoverer.ResponseReceivedCallback() { NetDiscoverer.discoverActiveUsers((ipAddr, data) -> {
@Override ActiveUser newUser = new ActiveUser(ipAddr);
public void onActiverUserDiscovered(ActiveUser user) { activeUsers.add(newUser);
activeUsers.add(user); pcs.firePropertyChange("activeUsers", null, newUser);
pcs.firePropertyChange("activeUsers", null, user);
}
}); });
} }