From ab5b05849803395faef86546790aca7b0d96f13d Mon Sep 17 00:00:00 2001 From: Yohan Simard Date: Mon, 30 Nov 2020 18:18:28 +0100 Subject: [PATCH] Implement network discovery methods (working) --- .../clavardator/network/NetDiscoverer.java | 170 ++++++++++++++---- .../fr/insa/clavardator/users/UserList.java | 11 +- 2 files changed, 139 insertions(+), 42 deletions(-) diff --git a/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java b/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java index 61468fe..8a55295 100644 --- a/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java +++ b/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java @@ -1,84 +1,184 @@ package fr.insa.clavardator.network; -import fr.insa.clavardator.users.ActiveUser; import fr.insa.clavardator.util.ErrorHandler; import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; +import java.net.*; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Objects; public class NetDiscoverer { - private static final short DISCOVERY_PORT = 31596; - private static final short RESPONSE_PORT = 31597; + private static final short DISCOVERY_PORT = 31593; + 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 - * @param callback + * Discovers all active users in the network, and call the callback for each of them + * + * @param callback function to call when a new user is discovered */ - public void sendBroadcast(String message, NetDiscoverer.ResponseReceivedCallback callback) { - NetDiscoverer.BroadcastSender sender = new NetDiscoverer.BroadcastSender(message, callback); + public static void discoverActiveUsers(ResponseReceivedCallback 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 { String broadcastMessage; - NetDiscoverer.ResponseReceivedCallback callback; /** * Constructs and starts a thread that sends a broadcast over the network + * * @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.callback = callback; - start(); } @Override public void run() { byte[] buf = broadcastMessage.getBytes(); try { - DatagramSocket broadcastSocket = new DatagramSocket(DISCOVERY_PORT); - broadcastSocket.setBroadcast(true); - broadcastSocket.bind(null); - broadcastSocket.send(new DatagramPacket(buf, buf.length)); + for (InetAddress broadcastAddr : listAllBroadcastAddresses()) { + DatagramSocket broadcastSocket = new DatagramSocket(); + broadcastSocket.setBroadcast(true); + broadcastSocket.send(new DatagramPacket(buf, buf.length, broadcastAddr, DISCOVERY_PORT)); +// System.out.println("Broadcast sent with address " + broadcastAddr.toString()); + } } catch (IOException e) { ErrorHandler.getInstance().notifyError(e); } - } } - private static class Listener extends Thread { - final short port; + private static class BroadcastListener extends Thread { + BroadcastReceivedCallback callback; - - public Listener(short port) { - this.port = port; + public BroadcastListener(BroadcastReceivedCallback callback) { + this.callback = callback; } @Override 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 listAllBroadcastAddresses() throws SocketException { + List broadcastList = new ArrayList<>(); + Enumeration 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 { - void onActiverUserDiscovered(ActiveUser user); - } - private interface ResponseSentCallback { - void onResponseSent(); + void onResponseReceived(InetAddress ipAddr, String data); } + private interface BroadcastReceivedCallback { - void onBroadcastReceived(InetAddress ipAddr); - } - private interface BroadcastSentCallback { - void onBroadcastSent(); + void onBroadcastReceived(InetAddress ipAddr, String data); } + } diff --git a/src/main/java/fr/insa/clavardator/users/UserList.java b/src/main/java/fr/insa/clavardator/users/UserList.java index d5835d9..4637b87 100644 --- a/src/main/java/fr/insa/clavardator/users/UserList.java +++ b/src/main/java/fr/insa/clavardator/users/UserList.java @@ -12,7 +12,6 @@ public class UserList { private ArrayList activeUsers; private ArrayList inactiveUsers; - private final NetDiscoverer netDiscoverer = new NetDiscoverer(); private final DatabaseController db = new DatabaseController(); // Make this class observable @@ -49,12 +48,10 @@ public class UserList { * */ public void discoverActiveUsers() { - netDiscoverer.sendBroadcast("", new NetDiscoverer.ResponseReceivedCallback() { - @Override - public void onActiverUserDiscovered(ActiveUser user) { - activeUsers.add(user); - pcs.firePropertyChange("activeUsers", null, user); - } + NetDiscoverer.discoverActiveUsers((ipAddr, data) -> { + ActiveUser newUser = new ActiveUser(ipAddr); + activeUsers.add(newUser); + pcs.firePropertyChange("activeUsers", null, newUser); }); }