/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package staticContent.evaluation.testbed.deploy.discovery; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.net.Socket; import java.net.SocketException; import java.net.SocketTimeoutException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.net.ssl.SSLSocketFactory; import javax.rmi.ssl.SslRMIClientSocketFactory; import org.apache.log4j.Logger; import staticContent.evaluation.testbed.deploy.utility.ConfigManager; import staticContent.evaluation.testbed.deploy.utility.NetworkUtility; import staticContent.evaluation.testbed.deploy.utility.ConfigManager.Type; public class DiscoveryHelper { private Map<String, String> collectedNodes = new ConcurrentHashMap<String, String>(); private ConfigManager config; protected Logger logger = Logger.getLogger(this.getClass()); private class DiscoveryClientUdpThread extends Thread { private DatagramPacket packet; public DiscoveryClientUdpThread(DatagramPacket packet) { this.packet = packet; } @Override public void run() { String data = new String(packet.getData(), 0, packet.getLength()); collectedNodes.put(data, packet.getAddress().getHostAddress()); logger.debug("response received from: "+packet.getAddress().getHostAddress()); } } private class DiscoveryClientSSLThread extends Thread { private String nodeAddress; private String registryAddress; private int registryPort; public DiscoveryClientSSLThread(String nodeAddress, String registryAddress, int registryPort) { this.nodeAddress = nodeAddress; this.registryAddress = registryAddress; this.registryPort = registryPort; } @Override public void run() { logger.debug("Try to open discovery connection to "+nodeAddress); try { SSLSocketFactory ssf = (SSLSocketFactory) SSLSocketFactory.getDefault(); Socket s = ssf.createSocket(nodeAddress, config.getInt("testnodeSSLPort")); String localAddress = s.getLocalAddress().getHostAddress(); System.setProperty("java.rmi.server.hostname", localAddress); if (NetworkUtility.isAdressLocal(registryAddress)) { registryAddress = localAddress; } String content = (registryAddress+":"+registryPort); // do something s.getOutputStream().write(content.getBytes(), 0, content.getBytes().length); logger.debug("Sent registry address "+localAddress+" and port "+registryPort+" to node: "+nodeAddress); byte[] uniqueIdBytes = new byte[45]; s.setSoTimeout(60000); s.getInputStream().read(uniqueIdBytes, 0, uniqueIdBytes.length); String uniqueId = new String(uniqueIdBytes, 0, uniqueIdBytes.length).trim(); collectedNodes.put(uniqueId, nodeAddress); s.close(); } catch (SocketException e) { // Appears when the timeout of the socket happens. // That means the testnode does not answer. // -> Do nothing in this case. // TODO: Nichtmal loggen? } catch (Exception e) { logger.error(e.getMessage(), e); } } } public DiscoveryHelper() { config = ConfigManager.getInstance(Type.COORDINATOR); } /** * Discovers the available test nodes via multicast. * The method blocks until the discovery finished. * * @return a Set with unique testnode names * * @throws IOException */ public Set<String> getAvailableNodesViaMulticast() throws IOException { collectedNodes.clear(); int sendPort = config.getInt("testnodeMulticastPort"); int receivePort = config.getInt("coordinatorMulticastPort"); String registryAddress = config.getString("registryAddress"); int registryPort = config.getInt("registryPort"); MulticastSocket socket = new MulticastSocket(receivePort); InetAddress group = InetAddress.getByName(config.getString("multicastAddress")); socket.joinGroup(group); byte[] content = (registryAddress+":"+registryPort).getBytes(); DatagramPacket packet = new DatagramPacket(content, content.length, group, sendPort); logger.debug("Sending multicast paket with registry adress " + registryAddress + " and port "+ registryPort +" to multicast address " + config.getString("multicastAddress")); socket.send(packet); boolean immediateResponse = config.getBoolean("multicastImmediateResponse"); socket.setSoTimeout((immediateResponse) ? 10000: 15000); try { while(true) { byte[] buf = new byte[256]; packet = new DatagramPacket(buf, buf.length); socket.receive(packet); (new DiscoveryClientUdpThread(packet)).start(); } } catch (SocketTimeoutException e) { // Appears when the timeout of the socket happens. // That means no further testnode answers. // -> The discovery ends here. socket.close(); return collectedNodes.keySet(); } } /** * Discovers the available test nodes via SSL connection on the basis of the given list of nodes. * The list should contain the node dns name or the ip address as String. * The method blocks until the discovery finished. * * @param nodes * @return a Set with unique testnode names * * @throws IOException */ public Set<String> getAvailableNodesWithPreconfiguredList(Collection<String> nodes) throws IOException { collectedNodes.clear(); String registryAddress = config.getString("registryAddress"); int registryPort = config.getInt("registryPort"); List<DiscoveryClientSSLThread> threads = new ArrayList<DiscoveryHelper.DiscoveryClientSSLThread>(); for(String nodeAddress: nodes) { DiscoveryClientSSLThread t = new DiscoveryClientSSLThread(nodeAddress, registryAddress, registryPort); threads.add(t); t.start(); } while(true) { boolean alive = false; for(DiscoveryClientSSLThread t: threads) { if (t.isAlive()) { alive = true; try { Thread.sleep(50); } catch (InterruptedException e) { } break; } } if (!alive) break; } return collectedNodes.keySet(); } /** * Discovers the available test nodes by asking the registry which testnodes are registered. * The method blocks until the discovery finished. * * @return a Set with unique testnode names * * @throws RemoteException */ public Set<String> getAvailableNodesFromRegistry() throws RemoteException { Set<String> result = new HashSet<String>(); Registry registry = LocateRegistry.getRegistry(config.getString("registryAddress"), config.getInt("registryPort"), new SslRMIClientSocketFactory()); for (String name : registry.list()) { if (name.startsWith("testnode_")) { result.add(name); } } return result; } }