/*******************************************************************************
* 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.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.rmi.ConnectException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import javax.net.ssl.SSLServerSocketFactory;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import staticContent.evaluation.testbed.deploy.testnode.Test;
import staticContent.evaluation.testbed.deploy.utility.ConfigManager;
import staticContent.evaluation.testbed.deploy.utility.NetworkUtility;
import staticContent.evaluation.testbed.deploy.utility.OSDetector;
import staticContent.evaluation.testbed.deploy.utility.ConfigManager.Type;
public class DiscoveryNode {
protected Logger logger = Logger.getLogger(this.getClass());
/**
* This Thread handles a single multicast discovery request.
*/
private class DiscoveryMulticastServerThread extends Thread {
private DatagramPacket packet;
public DiscoveryMulticastServerThread(DatagramPacket packet) {
this.packet = packet;
}
@Override
public void run() {
String data = new String(packet.getData(), 0, packet.getLength());
String[] dataTuple = data.split(":");
String registryHost = dataTuple[0];
int registryPort = Integer.parseInt(dataTuple[1]);
logger.debug("DiscoveryMulticastServerThread received message with registry location "+ registryHost +" at port "+registryPort);
InetAddress returnAdress = packet.getAddress();
try {
if (returnAdress.equals(NetworkUtility.getLocalIp().getHostAddress())) {
returnAdress = InetAddress.getLoopbackAddress();
}
} catch (UnknownHostException e) {
logger.error(e.getMessage(), e);
}
try {
//create test node
Test testNode = Test.getInstance();
byte[] reply = testNode.getUniqueId().getBytes();
int sendPort = config.getInt("coordinatorMulticastPort");
DatagramPacket pack = new DatagramPacket(reply, reply.length, returnAdress, sendPort);
DatagramSocket socket = new DatagramSocket();
boolean immediateResponse = config.getBoolean("multicastImmediateResponse");
if (immediateResponse) {
socket.send(pack);
}
if (NetworkUtility.isAdressLocal(registryHost)) {
registryHost = InetAddress.getLoopbackAddress().getHostAddress();
}
// test node rmi binding
testNode.bindToRegistry(registryHost,registryPort);
if (!immediateResponse) {
socket.send(pack);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
/**
* This Thread handles a single discovery request over an SSL connection.
*/
private class DiscoverySSLServerThread extends Thread {
private Socket s;
public DiscoverySSLServerThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
System.setProperty("java.rmi.server.hostname", s.getLocalAddress().getHostAddress());
byte[] inputBytes = new byte[32];
s.getInputStream().read(inputBytes, 0, inputBytes.length);
String data = new String(inputBytes, 0, inputBytes.length).trim();
String[] dataTuple = data.split(":");
String registryHost = dataTuple[0];
int registryPort = Integer.parseInt(dataTuple[1]);
logger.debug("DiscoverySSLServerThread received message with registry location "+ registryHost +" at port "+registryPort);
try{
//create test node
Test testNode = Test.getInstance();
byte[] reply = testNode.getUniqueId().getBytes();
if (NetworkUtility.isAdressLocal(registryHost)) {
registryHost = InetAddress.getLoopbackAddress().getHostAddress();
}
// test node rmi binding
testNode.bindToRegistry(registryHost, registryPort);
s.getOutputStream().write(reply, 0, reply.length);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
private ConfigManager config;
public DiscoveryNode() {
config = ConfigManager.getInstance(Type.TESTNODE);
}
/**
* Starts an SSL Server to handle discovery requests over SSL connection.
*
* @throws IOException
*/
public void startSSLServer() throws IOException {
int receivePort = config.getInt("testnodeSSLPort");
SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket ss = ssf.createServerSocket(receivePort);
logger.info("Node waiting for incoming SSL connections...");
while (true) {
Socket s = ss.accept();
(new DiscoverySSLServerThread(s)).start();
}
}
/**
* Starts a UDP multicast Server to handle discovery requests via multicast.
*
* @throws IOException
*/
private void startMulticastServer() throws IOException {
int receivePort = config.getInt("testnodeMulticastPort");
MulticastSocket socket = new MulticastSocket(receivePort);
InetAddress group = InetAddress.getByName(config.getString("multicastAddress"));
socket.joinGroup(group);
logger.info("Multicast listener started.");
byte[] buf;
DatagramPacket packet;
while(true) {
buf = new byte[21];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
logger.debug("packet received from: "+packet.getAddress().getHostAddress());
(new DiscoveryMulticastServerThread(packet)).start();
}
}
/**
* Starts a new thread that starts a UDP multicast Server to handle discovery requests via multicast.
*/
public void startMulticastHandler() {
final DiscoveryNode dn = this;
Thread multicastHandler = new Thread() {
@Override
public void run() {
try {
dn.startMulticastServer();
} catch (Exception e) {
logger.error("Creation of Multicast handler failed.", e);
}
}
};
multicastHandler.start();
}
/**
* Starts a new thread that starts an SSL Server to handle discovery requests over SSL connection.
*/
public void startSSLConnectionHandler() {
final DiscoveryNode dn = this;
Thread sslConnectionHandler = new Thread() {
@Override
public void run() {
try {
dn.startSSLServer();
} catch (Exception e) {
logger.error("Creation of SSL connection handler failed.", e);
}
}
};
sslConnectionHandler.start();
}
/**
* Creates a testnode instance and registers it at the registry.
*
* @throws RemoteException
* @throws NotBoundException
* @throws UnknownHostException
*/
public void registerTestnode() throws RemoteException, NotBoundException, UnknownHostException {
try{
//create test node
Test testNode = Test.getInstance();
String registryHost = config.getString("registryAddress");
int registryPort = config.getInt("registryPort");
if (NetworkUtility.isAdressLocal(registryHost)) {
registryHost = InetAddress.getLoopbackAddress().getHostAddress();
}
// test node rmi binding
testNode.bindToRegistry(registryHost, registryPort);
} catch (ConnectException | NotBoundException e) {
logger.error("Connect to registry failed. Try to connect again...");
registerTestnode();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// System.setProperty("javax.net.debug", "all");
if (OSDetector.isUnknown() || OSDetector.isWindows()) {
System.out.println("Sorry, your OS is not supported. Exiting...");
System.exit(1);
}
try {
// Set log4j configuration file path
PropertyConfigurator.configure(System.getProperty("user.dir") +"/inputOutput/testbed/config/log4j.properties");
ConfigManager cm = ConfigManager.getInstance(Type.TESTNODE);
System.setProperty("javax.net.ssl.keyStore", cm.getAbsoluteFilePath(System.getProperty("user.dir") +cm.getString("testnodeKeystorePath")));
System.setProperty("javax.net.ssl.keyStorePassword", cm.getString("testnodeKeystorePassword"));
System.setProperty("javax.net.ssl.trustStore", cm.getAbsoluteFilePath(System.getProperty("user.dir") +cm.getString("testnodeTruststorePath")));
System.setProperty("javax.net.ssl.trustStorePassword", cm.getString("testnodeTruststorePassword"));
String testnodeRegisterMode = cm.getString("testnodeRegisterMode");
DiscoveryNode server = new DiscoveryNode();
switch(testnodeRegisterMode) {
case "OnCreation" :
server.registerTestnode();
break;
case "Multicast" :
server.startMulticastHandler();
break;
case "OnCreationAndSSL" :
server.registerTestnode();
server.startSSLConnectionHandler();
break;
case "SSL" :
server.startSSLConnectionHandler();
break;
case "Both" :
default:
server.startMulticastHandler();
server.startSSLConnectionHandler();
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}