diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dbd1991..47285027 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ CHANGELOG ========= -2.0.0 (2018-XX-XX) +2.0.0 (2018-21-09) ------------------ -* Initial release \ No newline at end of file +* Initial release of POP-Java 2.0 \ No newline at end of file diff --git a/README.rst b/README.rst index d317f9a4..a1587b85 100755 --- a/README.rst +++ b/README.rst @@ -82,6 +82,16 @@ Netbeans Open the project as a Gradle project. Nothing more should be required. +Maven +~~~~~ + +.. code:: + + + ch.icosys + popjava + 2.0.0 + LICENCE ------- diff --git a/build.gradle b/build.gradle index 066712ad..2b8237e4 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ description = 'A Java distributed system' group = "ch.icosys" archivesBaseName = "popjava" -version = "1.5.3" +version = "2.0.2" sourceCompatibility = "1.8" targetCompatibility = "1.8" @@ -264,7 +264,7 @@ uploadArchives { licenses { license { name 'The GNU Lesser General Public License, Version 3.0' - url 'https://www.gnu.org/licenses/gpl-3.0.txt' + url 'https://www.gnu.org/licenses/lgpl-3.0.txt' } } diff --git a/docs/dev/contributing.rst b/docs/dev/contributing.rst index 6adacd71..71262dc2 100644 --- a/docs/dev/contributing.rst +++ b/docs/dev/contributing.rst @@ -10,7 +10,7 @@ Coding conventions When writing new code for POP-Java you should always: -* Indent with a hard-tab ``\t``, ASCII ``0x09`` +* Indent with 4 spaces * Always surround blocks with ``{ }`` * ... * ... @@ -85,6 +85,14 @@ Creation of a new release ossrhPassword=your-jira-password * The signing data must be generated, e.g. with `GnuPG `_. + * Newer (2.1+) GPG versions use a new keyring file format (.kbx). You need to convert/export your key to the old format. + + ``gpg --export-secret-keys -o secring.gpg`` + + * With the 2.1+ GPG version you also need to use a special command to list the available keys to get the correct id. + + ``gpg --list-keys --keyid-format short`` + * More information about the Maven packaging process is given on the `OSSRH Guide `_. @@ -123,4 +131,5 @@ Creation of a new release .. note:: * To pass this step, the deployed files are verified and thus must fulfil some `requirements `_. * This step was fully automatized thanks to the `Gradle Nexus Staging Plugin `_. However, it can manually be done on the `OSSRH website `_ as described `here `_. + * It takes about 2 hours to synchronize between OSSRH and the Central Repository diff --git a/workspace/popjava/src/ch/icosys/popjava/core/base/POPObject.java b/workspace/popjava/src/ch/icosys/popjava/core/base/POPObject.java index 88704816..da205c6e 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/base/POPObject.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/base/POPObject.java @@ -730,15 +730,15 @@ public void exit() { */ public void printMethodInfo() { System.out.println("===========ConstructorInfo============"); - constructorInfos.forEach((mi, c) -> System.out.format("ClassId:%d.ConstructorId:%d.Sign:%s", mi.getClassId(), + constructorInfos.forEach((mi, c) -> System.out.format("ClassId:%d.ConstructorId:%d.Sign:%s\n", mi.getClassId(), mi.getMethodId(), c.toGenericString())); System.out.println("===========MethodInfo============"); - methodInfos.forEach((mi, m) -> System.out.format("ClassId:%d.MethodId:%d.Sign:%s", mi.getClassId(), + methodInfos.forEach((mi, m) -> System.out.format("ClassId:%d.MethodId:%d.Sign:%s\n", mi.getClassId(), mi.getMethodId(), m.toGenericString())); System.out.println("===========SemanticsInfo============"); - semantics.forEach((mi, s) -> System.out.format("ClassId:%d.ConstructorId:%d.Semantics:%d", mi.getClassId(), + semantics.forEach((mi, s) -> System.out.format("ClassId:%d.ConstructorId:%d.Semantics:%d\n", mi.getClassId(), mi.getMethodId(), s)); } diff --git a/workspace/popjava/src/ch/icosys/popjava/core/baseobject/AccessPoint.java b/workspace/popjava/src/ch/icosys/popjava/core/baseobject/AccessPoint.java index 8ab46c17..e3e3e8fa 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/baseobject/AccessPoint.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/baseobject/AccessPoint.java @@ -4,6 +4,7 @@ import ch.icosys.popjava.core.system.POPSystem; import ch.icosys.popjava.core.util.Configuration; +import ch.icosys.popjava.core.util.SystemUtil; /** * This class represent an access to a broker-side parallel object @@ -187,6 +188,14 @@ public boolean isEmpty() { return false; } + /** + * Returns true if the IP/Host is in a private subnet + * @return + */ + public boolean isPrivateIP() { + return SystemUtil.isHostInPrivateSubnet(host); + } + /** * Format the access point as a string value */ diff --git a/workspace/popjava/src/ch/icosys/popjava/core/baseobject/POPAccessPoint.java b/workspace/popjava/src/ch/icosys/popjava/core/baseobject/POPAccessPoint.java index 7eb897a2..12e39a82 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/baseobject/POPAccessPoint.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/baseobject/POPAccessPoint.java @@ -218,6 +218,16 @@ public boolean hasSameAccessPoint(POPAccessPoint ap) { return false; } + + public boolean hasAccessPointIP(String ip) { + for (int i = 0; i < accessPoints.size(); i++) { + if(accessPoints.get(i).getHost().equals(ip)){ + return true; + } + } + + return false; + } @Override public int hashCode() { diff --git a/workspace/popjava/src/ch/icosys/popjava/core/broker/Broker.java b/workspace/popjava/src/ch/icosys/popjava/core/broker/Broker.java index ab65b0f5..c930f6f3 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/broker/Broker.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/broker/Broker.java @@ -511,6 +511,9 @@ private boolean invokeMethod(Request request) throws InterruptedException { } catch (NoSuchMethodException e) { exception = POPException.createReflectMethodNotFoundException(popInfo.getClass().getName(), request.getClassId(), request.getMethodId(), e.getMessage()); + + popInfo.printMethodInfo(); + System.out.println(accessPoint); } if (method != null) { @@ -673,7 +676,7 @@ private boolean invokeMethod(Request request) throws InterruptedException { } } - if (tracking && remote != null) { + if (tracking && remote != null && method != null) { registerTracking(remote, method.toGenericString(), trackingTime, inputSize, outputSize); } @@ -724,7 +727,7 @@ public boolean invoke(Request request) throws InterruptedException { remoteCaller.set(caller); // check for localhost only execution and throw exception if we can't - if (request.isLocalhost() && !caller.isLocalHost()) { + if (request.isLocalhost() && !caller.isLocalHost(accessPoint)) { if (request.isSynchronous()) { POPException exception = new POPException(POPErrorCode.METHOD_ANNOTATION_EXCEPTION, "You can't call a localhost method from a remote location. "+caller.getRemote().getHostAddress()); @@ -1068,11 +1071,6 @@ public boolean initialize(List argvs) { // hadle multiple times the same protocol String port; while ((port = Util.removeStringFromList(argvs, prefix)) != null) { - // if we don't have a port, abort - /* - * if (port == null) { continue; } - */ - int iPort = 0; if (port.length() > 0) { try { @@ -1105,8 +1103,9 @@ public boolean initialize(List argvs) { if (externalIP != null && !externalIP.isEmpty()) { for (int i = 0; i < accessPoint.size(); i++) { AccessPoint ap = new AccessPoint(accessPoint.get(i)); - // TODO: The port might also be diferent ap.setHost(externalIP); + + UPNPManager.mapAccessPoint(ap, 1000); accessPoint.addAccessPoint(ap); } diff --git a/workspace/popjava/src/ch/icosys/popjava/core/combox/Combox.java b/workspace/popjava/src/ch/icosys/popjava/core/combox/Combox.java index 6187e055..60deeabc 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/combox/Combox.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/combox/Combox.java @@ -185,7 +185,9 @@ public void run() { if (System.currentTimeMillis() - lastCommunication > KEEP_ALIVE_INTERVAL) { POPBuffer buffer = createServicePacket(PING); - send(buffer); + if(send(buffer) < 0) { + break; + } } } diff --git a/workspace/popjava/src/ch/icosys/popjava/core/combox/ComboxUtils.java b/workspace/popjava/src/ch/icosys/popjava/core/combox/ComboxUtils.java index 3232fa3c..c469f93d 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/combox/ComboxUtils.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/combox/ComboxUtils.java @@ -8,6 +8,7 @@ import javax.net.ServerSocketFactory; import ch.icosys.popjava.core.util.Configuration; +import ch.icosys.popjava.core.util.Tuple; import ch.icosys.popjava.core.util.upnp.UPNPManager; /** @@ -90,7 +91,7 @@ private static ServerSocket createServerSocket(int port, PreOperation op, boolea if (upnp) { @SuppressWarnings("unused") - Future externalIP = UPNPManager.registerPort(server.getLocalPort()); + Future> externalIP = UPNPManager.registerPort(server.getLocalPort()); } return server; diff --git a/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/ComboxSocket.java b/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/ComboxSocket.java index 08f77d8a..b78f86b7 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/ComboxSocket.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/ComboxSocket.java @@ -20,6 +20,7 @@ import ch.icosys.popjava.core.buffer.POPBuffer; import ch.icosys.popjava.core.combox.Combox; import ch.icosys.popjava.core.util.LogWriter; +import ch.icosys.popjava.core.util.SystemUtil; public abstract class ComboxSocket extends Combox { @@ -285,14 +286,19 @@ public void closeInternal() { } } catch (IOException e) { } finally { - try { - outputStream.close(); - } catch (IOException e) { + if(outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + } } - try { - inputStream.close(); - } catch (IOException e) { + if(inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + } } + if (peerConnection != null) { try { peerConnection.close(); @@ -369,8 +375,8 @@ public int compare(AccessPoint o1, AccessPoint o2) { return 1; } - boolean privateSubnet1 = isHostInPrivateSubnet(o1.getHost()); - boolean privateSubnet2 = isHostInPrivateSubnet(o2.getHost()); + boolean privateSubnet1 = SystemUtil.isHostInPrivateSubnet(o1.getHost()); + boolean privateSubnet2 = SystemUtil.isHostInPrivateSubnet(o2.getHost()); if (privateSubnet1 && !privateSubnet2) { return 1; @@ -391,8 +397,4 @@ public int compare(AccessPoint o1, AccessPoint o2) { return aps; } - - private static boolean isHostInPrivateSubnet(String host) { - return host.startsWith("10.") || host.startsWith("172.16.") || host.startsWith("192.168."); - } } diff --git a/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/raw/ComboxRawSocket.java b/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/raw/ComboxRawSocket.java index 97813a85..4976ab37 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/raw/ComboxRawSocket.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/raw/ComboxRawSocket.java @@ -53,29 +53,31 @@ protected boolean connectToServer() { for (int i = 0; i < aps.size() && !available; i++) { AccessPoint ap = aps.get(i); - - String host = ap.getHost(); - int port = ap.getPort(); - try { - // Create an unbound socket - if (timeOut > 0) { - SocketAddress sockaddress = new InetSocketAddress(host, port); - peerConnection = new Socket(); - peerConnection.connect(sockaddress, timeOut); - - // LogWriter.writeExceptionLog(new Exception()); - // LogWriter.writeExceptionLog(new Exception("Open - // connection to "+host+":"+port+" remote: - // "+peerConnection.getLocalPort())); - } else { - peerConnection = new Socket(host, port); + + if(ap.getProtocol().equals(ComboxSocketFactory.PROTOCOL)) { + String host = ap.getHost(); + int port = ap.getPort(); + try { + // Create an unbound socket + if (timeOut > 0) { + SocketAddress sockaddress = new InetSocketAddress(host, port); + peerConnection = new Socket(); + peerConnection.connect(sockaddress, timeOut); + + // LogWriter.writeExceptionLog(new Exception()); + // LogWriter.writeExceptionLog(new Exception("Open + // connection to "+host+":"+port+" remote: + // "+peerConnection.getLocalPort())); + } else { + peerConnection = new Socket(host, port); + } + inputStream = new BufferedInputStream(peerConnection.getInputStream()); + outputStream = new BufferedOutputStream(peerConnection.getOutputStream()); + available = true; + } catch (IOException e) { + available = false; + LogWriter.writeExceptionLog(e); } - inputStream = new BufferedInputStream(peerConnection.getInputStream()); - outputStream = new BufferedOutputStream(peerConnection.getOutputStream()); - available = true; - } catch (IOException e) { - available = false; - LogWriter.writeExceptionLog(e); } } return available; diff --git a/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/ssl/ComboxSecureSocket.java b/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/ssl/ComboxSecureSocket.java index 35f3f7c8..5aba5b33 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/ssl/ComboxSecureSocket.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/combox/socket/ssl/ComboxSecureSocket.java @@ -68,48 +68,50 @@ protected boolean connectToServer() { for (int i = 0; i < aps.size() && !available; i++) { AccessPoint ap = aps.get(i); - - String host = ap.getHost(); - int port = ap.getPort(); - - try { - // Create an unbound socket - SocketAddress sockaddress = new InetSocketAddress(host, port); - if (timeOut > 0) { - peerConnection = (SSLSocket) factory.createSocket(); - - // LogWriter.writeExceptionLog(new Exception()); - // LogWriter.writeExceptionLog(new Exception("Open - // connection to "+host+":"+port+" remote: - // "+peerConnection.getLocalPort())); - } else { - peerConnection = (SSLSocket) factory.createSocket(); - timeOut = 0; + + if(ap.getProtocol().equals(ComboxSecureSocketFactory.PROTOCOL)) { + String host = ap.getHost(); + int port = ap.getPort(); + + try { + // Create an unbound socket + SocketAddress sockaddress = new InetSocketAddress(host, port); + if (timeOut > 0) { + peerConnection = (SSLSocket) factory.createSocket(); + + // LogWriter.writeExceptionLog(new Exception()); + // LogWriter.writeExceptionLog(new Exception("Open + // connection to "+host+":"+port+" remote: + // "+peerConnection.getLocalPort())); + } else { + peerConnection = (SSLSocket) factory.createSocket(); + timeOut = 0; + } + peerConnection.setUseClientMode(true); + + // setup SNI + SNIServerName network = new SNIHostName(getNetworkUUID()); + List nets = new ArrayList<>(1); + nets.add(network); + + // set SNI as part of the parameters + SSLParameters parameters = peerConnection.getSSLParameters(); + parameters.setServerNames(nets); + peerConnection.setSSLParameters(parameters); + + // connect and start handshake + peerConnection.connect(sockaddress); + + // setup communication buffers + inputStream = new BufferedInputStream(peerConnection.getInputStream()); + outputStream = new BufferedOutputStream(peerConnection.getOutputStream()); + + available = true; + } catch (IOException e) { + exceptions.add(e); + available = false; } - peerConnection.setUseClientMode(true); - - // setup SNI - SNIServerName network = new SNIHostName(getNetworkUUID()); - List nets = new ArrayList<>(1); - nets.add(network); - - // set SNI as part of the parameters - SSLParameters parameters = peerConnection.getSSLParameters(); - parameters.setServerNames(nets); - peerConnection.setSSLParameters(parameters); - - // connect and start handshake - peerConnection.connect(sockaddress); - - // setup communication buffers - inputStream = new BufferedInputStream(peerConnection.getInputStream()); - outputStream = new BufferedOutputStream(peerConnection.getOutputStream()); - - available = true; - } catch (IOException e) { - exceptions.add(e); - available = false; - } + } } } catch (Exception e) { e.printStackTrace(); diff --git a/workspace/popjava/src/ch/icosys/popjava/core/interfacebase/Interface.java b/workspace/popjava/src/ch/icosys/popjava/core/interfacebase/Interface.java index c5958f5d..aac813da 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/interfacebase/Interface.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/interfacebase/Interface.java @@ -423,7 +423,7 @@ protected boolean bind(POPAccessPoint accesspoint) throws POPException { networkUUID = conf.getDefaultNetwork(); } combox = new ComboxConnection(factory.createClientCombox(networkUUID), 1); - } catch (IOException e) { + } catch (Throwable e) { LogWriter.writeExceptionLog(e); continue; } diff --git a/workspace/popjava/src/ch/icosys/popjava/core/scripts/Popjrun.java b/workspace/popjava/src/ch/icosys/popjava/core/scripts/Popjrun.java index 1d7b3ee6..31a72286 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/scripts/Popjrun.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/scripts/Popjrun.java @@ -216,7 +216,9 @@ private static void runForkedApplication(String main, String objectMap, List hostIPS = POPSystem.getAllHostIPs(true); + List hostIPSReduced = new ArrayList<>(hostIPS); List duplicates = new ArrayList<>(); for(int i = 0; i < me.size(); i++) { AccessPoint ap = me.get(i); - if(hostIPS.contains(ap.getHost())) { - hostIPS.remove(ap.getHost()); + for(InterfaceAddress iAHost : hostIPS) { + if(iAHost.getAddress().getHostAddress().equals(ap.getHost())) { + hostIPSReduced.remove(iAHost); + } } for(String host : hostnames) { @@ -1932,7 +1955,7 @@ private POPAccessPoint getGeneralizedAccessPoint() { for(int i = 0; i < me.size(); i++) { AccessPoint ap = me.get(i); - for(InterfaceAddress localIP : hostIPS) { + for(InterfaceAddress localIP : hostIPSReduced) { duplicates.add(new AccessPoint(ap.getProtocol(), localIP.getAddress().getHostAddress(), ap.getPort())); } } @@ -1996,8 +2019,12 @@ public void rerouteResponse(@POPParameter(Direction.IN) SNResponse response, // get next node to contact POPAccessPoint jm = wayback.pop(); POPJavaJobManager njm = connectToJobmanager(jm, response.getNetworkUUID()); - // route request through it - njm.rerouteResponse(response, wayback); + if(njm != null) { + // route request through it + njm.rerouteResponse(response, wayback); + }else { + LogWriter.writeDebugInfo("[PSN] Unable to reroute response ;%s;DEST;%s", response.getUID(), wayback.toString()); + } } // is the last node, give the answer to the original JM who // launched the request else { @@ -2038,6 +2065,38 @@ public boolean knowsJobManager(String network, POPAccessPoint ap) { private final Set> jmConnectionLock = Collections.synchronizedSet(new HashSet<>()); + private final Map, FutureTask> jmConnectorThreads = Collections.synchronizedMap(new HashMap<>()); + + private POPJavaJobManager connectToJM(POPAccessPoint ap, String network) { + final POPJavaJobManager me = this; + + FutureTask task = new FutureTask<>(new Callable() { + + @Override + public POPJavaJobManager call() throws Exception { + return PopJava.connect(me, POPJavaJobManager.class, network, ap); + } + }); + + + Tuple key = new Tuple(network, ap); + jmConnectorThreads.put(key, task); + + Thread thread = new Thread(task); + thread.setDaemon(true); + thread.start(); + + POPJavaJobManager jm = null; + try { + jm = task.get(10, TimeUnit.SECONDS); + }catch (Exception e) { + } + + jmConnectorThreads.remove(key); + + return jm; + } + public POPJavaJobManager connectToJobmanager(POPAccessPoint ap, String network) throws InterruptedException { Tuple key = new Tuple(network, ap); @@ -2053,27 +2112,36 @@ public POPJavaJobManager connectToJobmanager(POPAccessPoint ap, String network) try { //Connect to JM first time if necessary if (!cachedJobManangers.containsKey(key)) { - POPJavaJobManager jm = PopJava.connect(this, POPJavaJobManager.class, network, ap); - - cachedJobManangers.put(key, jm); + LogWriter.writeDebugInfo("[PSN] JM unknown, connect to " + ap+" "+network+" "+System.currentTimeMillis()); + POPJavaJobManager jm = connectToJM(ap, network); + if(jm != null) { + LogWriter.writeDebugInfo("[PSN] Connection open " + ap+" "+network+" "+System.currentTimeMillis()); + cachedJobManangers.put(key, jm); + }else { + LogWriter.writeDebugInfo("[PSN] Connection failed " + ap+" "+network+" "+System.currentTimeMillis()); + } } POPJavaJobManager jm = cachedJobManangers.get(key); - try { - //Check if the neighbour knows us, this also implicitely tests the connection - POPAccessPoint myAP = getAccessPoint(); - - jm.registerNeighbourJobmanager(getAccessPoint(), network, this); - /*if(!jm.knowsJobManager(network, myAP)) { + if(jm != null) { + try { + //Check if the neighbour knows us, this also implicitely tests the connection + POPAccessPoint myAP = getAccessPoint(); + LogWriter.writeDebugInfo("[PSN] Register self at " + ap+" "+network+" "+System.currentTimeMillis()); jm.registerNeighbourJobmanager(getAccessPoint(), network, this); - }*/ - } catch (Exception e) { - //If the connection we have is down, reconnect - cachedJobManangers.remove(key); - jm = PopJava.connect(this, POPJavaJobManager.class, network, ap); + /*if(!jm.knowsJobManager(network, myAP)) { + jm.registerNeighbourJobmanager(getAccessPoint(), network, this); + }*/ + } catch (Exception e) { + LogWriter.writeDebugInfo("[PSN] JM not available, reconnect to " + ap+" "+network+" "+System.currentTimeMillis()); + + //If the connection we have is down, reconnect + cachedJobManangers.remove(key); + jm = connectToJM(ap, network); - cachedJobManangers.put(key, jm); + cachedJobManangers.put(key, jm); + } } return jm; @@ -2088,28 +2156,44 @@ public POPJavaJobManager connectToJobmanager(POPAccessPoint ap, String network) @POPSyncConc public POPAccessPoint[] newTFCSearchOn(POPAccessPoint ap, String network, String objectName) { try { - return connectToJobmanager(ap, network).localTFCSearch(network, objectName); + POPJavaJobManager jm = connectToJobmanager(ap, network); + + if(jm != null) { + return jm.localTFCSearch(network, objectName); + } }catch (InterruptedException e) { - return new POPAccessPoint[0]; } - + + return new POPAccessPoint[0]; } @POPSyncConc public void registerNeighbourJobmanager(POPAccessPoint ap, String network, POPJavaJobManager jm) { + + LogWriter.writeDebugInfo("[PSN] register " + ap+" "+network); + Tuple key = new Tuple(network, ap); if (!cachedJobManangers.containsKey(key)) { + LogWriter.writeDebugInfo("[PSN] JM was unknown, keep connection " + ap+" "+network); jm.makePermanent(); cachedJobManangers.put(key, jm); + + if(jmConnectorThreads.containsKey(key)) { + jmConnectorThreads.get(key).cancel(true); + } } else { try { POPJavaJobManager current = cachedJobManangers.get(key); POPString val = new POPString(); current.query("power", val); + + LogWriter.writeDebugInfo("[PSN] JM was known, keep old " + ap+" "+network); } catch (Exception e) { jm.makePermanent(); cachedJobManangers.put(key, jm); + + LogWriter.writeDebugInfo("[PSN] Old JM unavailabe, keep new " + ap+" "+network); } } } diff --git a/workspace/popjava/src/ch/icosys/popjava/core/system/POPSystem.java b/workspace/popjava/src/ch/icosys/popjava/core/system/POPSystem.java index 304cb090..e9b2d4ae 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/system/POPSystem.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/system/POPSystem.java @@ -30,6 +30,8 @@ import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import javassist.util.proxy.ProxyFactory; + import ch.icosys.popjava.core.PopJava; import ch.icosys.popjava.core.base.POPException; import ch.icosys.popjava.core.baseobject.ObjectDescription; @@ -44,7 +46,6 @@ import ch.icosys.popjava.core.util.Util; import ch.icosys.popjava.core.util.Util.OSType; import ch.icosys.popjava.core.util.upnp.UPNPManager; -import javassist.util.proxy.ProxyFactory; /** * This class is responsible for the initialization of a POP-Java application. @@ -61,6 +62,18 @@ public class POPSystem { private static final List localHooks = new ArrayList<>(); + private static final Configuration conf = Configuration.getInstance(); + + private static String jobservice = String.format("%s:%d", POPSystem.getHostIP().getAddress().getHostAddress(), conf.getJobManagerPorts()[0]); + + private static String codeconf; + + private static String appservicecode; + + private static String proxy; + + private static String appservicecontact; + /** * POP-Java location environement variable name */ @@ -72,43 +85,41 @@ public class POPSystem { public static POPAccessPoint jobService = new POPAccessPoint(); private static AppService coreServiceManager; - // private static POPJobService jobmanager; /** * POP-Java application service access point */ public static POPAccessPoint appServiceAccessPoint = new POPAccessPoint(); - private static final Configuration conf = Configuration.getInstance(); - public static void writeLog(String log) { if (!conf.isDebug()) { System.out.println(log); } LogWriter.writeDebugInfo(log); - /* - * try { POPAppService app = - * (POPAppService)PopJava.newActive(POPAppService.class, - * POPSystem.AppServiceAccessPoint); if(app != null){ - * app.logPJ(app.getPOPCAppID(), log); }else{ System.out.println(log); } - * - * } catch (Exception e) { System.out.println(log); try{ POPAppService app = - * (POPAppService)PopJava.newActive(POPJavaAppService.class, - * POPSystem.AppServiceAccessPoint); app.logPJ(app.getPOPCAppID(), log); } catch - * (POPException e2) { e2.printStackTrace(); } } - */ } static { // Trick :(( I don't know why the system i386 doesn't work - String osName = System.getProperty("os.name"); - String osArchitect = System.getProperty("os.arch"); + try { + String osName = System.getProperty("os.name"); + String osArchitect = System.getProperty("os.arch"); - if (osArchitect.contains("64")) { - osArchitect = "x86_64"; - } + if(osName == null) { + osName = ""; + } + + if(osArchitect == null) { + osArchitect = ""; + } + + if (osArchitect.contains("64")) { + osArchitect = "x86_64"; + } - platform = String.format("%s-%s", osArchitect, osName); + platform = String.format("%s-%s", osArchitect, osName); + }catch (Throwable e) { + e.printStackTrace(); + } } /** @@ -179,7 +190,7 @@ public static InterfaceAddress getHostIP() { } //Find first non local address - Enumeration en; + Enumeration en = null; try { en = NetworkInterface.getNetworkInterfaces(); while (en.hasMoreElements()) { @@ -194,26 +205,52 @@ public static InterfaceAddress getHostIP() { } //Find first non local address - try { - en = NetworkInterface.getNetworkInterfaces(); + if(en != null) { while (en.hasMoreElements()) { NetworkInterface ni = en.nextElement(); InterfaceAddress ip = getInterfaceIP(ni, true); if (ip != null) { return ip; } - } - } catch (SocketException e) { } - + try { InetAddress localHost = Inet4Address.getLocalHost(); NetworkInterface networkInterface = NetworkInterface.getByInetAddress(localHost); - for(InterfaceAddress addr : networkInterface.getInterfaceAddresses()) { - if(addr.getAddress().isLoopbackAddress() && addr.getAddress() instanceof Inet4Address) { - return addr; + if(networkInterface != null) { + for(InterfaceAddress addr : networkInterface.getInterfaceAddresses()) { + if(addr.getAddress().isLoopbackAddress() && addr.getAddress() instanceof Inet4Address) { + return addr; + } + } + + //Fallback to whatever we find + for(InterfaceAddress addr : networkInterface.getInterfaceAddresses()) { + if(addr.getAddress() instanceof Inet4Address) { + return addr; + } + } + }else { + en = NetworkInterface.getNetworkInterfaces(); + while (en.hasMoreElements()) { + NetworkInterface ni = en.nextElement(); + + for (InterfaceAddress interfaceAddress : ni.getInterfaceAddresses()) { + + if(interfaceAddress.getAddress() instanceof Inet4Address) { + return interfaceAddress; + } + } + } + + while (en.hasMoreElements()) { + NetworkInterface ni = en.nextElement(); + + for (InterfaceAddress interfaceAddress : ni.getInterfaceAddresses()) { + return interfaceAddress; + } } } }catch (SocketException e) { @@ -387,16 +424,6 @@ public static void registerCode(String file, String clazz) { } } - private static String jobservice = String.format("%s:%d", POPSystem.getHostIP().getAddress().getHostAddress(), conf.getJobManagerPorts()[0]); - - private static String codeconf; - - private static String appservicecode; - - private static String proxy; - - private static String appservicecontact; - /** * Initialize the application scope services * diff --git a/workspace/popjava/src/ch/icosys/popjava/core/util/Configuration.java b/workspace/popjava/src/ch/icosys/popjava/core/util/Configuration.java index b9bff472..58c196a5 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/util/Configuration.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/util/Configuration.java @@ -42,10 +42,10 @@ private enum Settable { private static final Boolean ENV_DEBUG; static { String location = System.getenv("POPJAVA_LOCATION"); - if (location == null) { - POPJAVA_LOCATION = new File("./").getAbsolutePath(); - } else { + if (location != null) { POPJAVA_LOCATION = new File(location).getAbsolutePath(); + } else { + POPJAVA_LOCATION = new File("./").getAbsolutePath(); } String debug = System.getenv("POPJAVA_DEBUG"); diff --git a/workspace/popjava/src/ch/icosys/popjava/core/util/POPRemoteCaller.java b/workspace/popjava/src/ch/icosys/popjava/core/util/POPRemoteCaller.java index 920a82aa..488fa64c 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/util/POPRemoteCaller.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/util/POPRemoteCaller.java @@ -102,7 +102,11 @@ public boolean isUsingConfidenceLink() { * * @return true if the address is our own machine */ - public boolean isLocalHost() { + public boolean isLocalHost(POPAccessPoint ap) { + if(ap.hasAccessPointIP(remote.getHostAddress())) { + return true; + } + return Util.isLocal(remote.getHostAddress()); } diff --git a/workspace/popjava/src/ch/icosys/popjava/core/util/SystemUtil.java b/workspace/popjava/src/ch/icosys/popjava/core/util/SystemUtil.java index 939b18dd..0cb9a64c 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/util/SystemUtil.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/util/SystemUtil.java @@ -370,4 +370,20 @@ public static synchronized void registerLocalJVM(Broker broker) { Objects.requireNonNull(broker); localJVM.add(broker); } + + public static boolean isHostInPrivateSubnet(String host) { + if(host.startsWith("10.") || host.startsWith("192.168.")) { + return true; + } + + if(host.startsWith("172.")) { + for(int i = 16; i < 32; i++) { + if(host.startsWith("172."+i+".")) { + return true; + } + } + } + + return false; + } } diff --git a/workspace/popjava/src/ch/icosys/popjava/core/util/upnp/UPNPManager.java b/workspace/popjava/src/ch/icosys/popjava/core/util/upnp/UPNPManager.java index 10d51cad..9d58df6d 100644 --- a/workspace/popjava/src/ch/icosys/popjava/core/util/upnp/UPNPManager.java +++ b/workspace/popjava/src/ch/icosys/popjava/core/util/upnp/UPNPManager.java @@ -5,12 +5,17 @@ import java.net.SocketException; import java.net.UnknownHostException; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import javax.xml.parsers.ParserConfigurationException; @@ -19,7 +24,9 @@ import org.bitlet.weupnp.PortMappingEntry; import org.xml.sax.SAXException; +import ch.icosys.popjava.core.baseobject.AccessPoint; import ch.icosys.popjava.core.util.LogWriter; +import ch.icosys.popjava.core.util.Tuple; public class UPNPManager { @@ -29,7 +36,8 @@ public class UPNPManager { private static GatewayDevice d = null; - private static final Set mappedPorts = Collections.synchronizedSet(new HashSet()); + private static final Map mappedPorts = Collections.synchronizedMap(new HashMap<>()); + private static final Map>> mappingTasks = Collections.synchronizedMap(new HashMap<>()); private static boolean inited = false; @@ -67,15 +75,15 @@ public synchronized static String getExternalIP() { return externalIP; } - public synchronized static Future registerPort(int port) { - if (mappedPorts.contains(port)) { - return CompletableFuture.completedFuture(externalIP); + public synchronized static Future> registerPort(int port) { + if (mappedPorts.containsKey(port)) { + return CompletableFuture.completedFuture(new Tuple(externalIP, mappedPorts.get(port))); } - Callable mapper = new Callable() { + Callable> mapper = new Callable>() { @Override - public String call() throws Exception { + public Tuple call() throws Exception { init(); if (null != d) { @@ -83,9 +91,11 @@ public String call() throws Exception { "Found gateway device.\n" + d.getModelName() + " (" + d.getModelDescription() + ")"); } else { LogWriter.writeDebugInfo("No valid gateway device found."); - return ""; + return new Tuple("", -1); } + int newPort = port; + InetAddress localAddress = d.getLocalAddress(); String externalIPAddress = ""; try { @@ -96,15 +106,30 @@ public String call() throws Exception { PortMappingEntry portMapping = new PortMappingEntry(); + boolean directMapping = false; if (d.getSpecificPortMappingEntry(port, "TCP", portMapping)) { - LogWriter.writeDebugInfo("Port " + port + " is already forwarded"); - } else { + if(portMapping.getInternalClient().equals(localAddress.getHostAddress())) { + directMapping = true; + LogWriter.writeDebugInfo("Port " + port + " is already forwarded to ourself"); + }else { + LogWriter.writeDebugInfo("Port " + port + " is already forwarded to "+portMapping.getInternalClient()); + newPort = getFreeNATPort(localAddress, port); + if(newPort < 0) { + newPort *= -1; + LogWriter.writeDebugInfo("Remap of " + port + " to "+newPort+" is already in place"); + directMapping = true; + }else { + LogWriter.writeDebugInfo("Remap " + port + " to "+newPort); + } + } + } + + if(!directMapping) { LogWriter.writeDebugInfo("Sending port mapping request"); - if (!d.addPortMapping(port, port, localAddress.getHostAddress(), "TCP", "POP-Java")) { + if (!d.addPortMapping(newPort, port, localAddress.getHostAddress(), "TCP", "POP-Java")) { LogWriter.writeDebugInfo("Port mapping attempt failed"); - } else { - mappedPorts.add(port); + newPort = -1; } } } catch (SAXException e) { @@ -112,26 +137,90 @@ public String call() throws Exception { } catch (IOException e) { LogWriter.writeExceptionLog(e); } - - return externalIP; + + if(newPort != -1) { + mappedPorts.put(port, newPort); + } + + mappingTasks.remove(port); + + return new Tuple(externalIP, newPort); } }; - FutureTask task = new FutureTask<>(mapper); + FutureTask> task = new FutureTask<>(mapper); Thread upnpThread = new Thread(task); upnpThread.setDaemon(true); upnpThread.start(); + + mappingTasks.put(port, task); return task; } + + public static void mapAccessPoint(final AccessPoint ap, long timeOutMS) { + Future> futurePort = mappingTasks.get(ap.getPort()); + + if(mappedPorts.containsKey(ap.getPort())) { + ap.setPort(mappedPorts.get(ap.getPort())); + } + + if(futurePort != null) { + + Thread thread = new Thread(new Runnable() { + + @Override + public void run() { + try { + ap.setPort(futurePort.get(2, TimeUnit.SECONDS).getB()); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } catch (TimeoutException e) { + e.printStackTrace(); + } + } + }); + thread.setDaemon(true); + thread.start(); + + try { + thread.join(timeOutMS); + } catch (InterruptedException e) { + } + } + } + + private static int getFreeNATPort(InetAddress localAddress, int port) throws IOException, SAXException { + + int counter = 0; + do { + port++; + PortMappingEntry portMapping = new PortMappingEntry(); + if (!d.getSpecificPortMappingEntry(port, "TCP", portMapping)) { + return port; + } + + if(portMapping.getInternalClient().equals(localAddress.getHostAddress())) { + return -port; + } + + //Abort after 1000 ports + if(counter++ > 1000) { + return 0; + } + }while(true); + + } public static synchronized void close() { if (mappedPorts.size() > 0) { GatewayDevice d = discover.getValidGateway(); - for (int port : mappedPorts) { + for (int port : mappedPorts.keySet()) { try { d.deletePortMapping(port, "TCP"); } catch (IOException e) { diff --git a/workspace/popjava/test/ch/icosys/popjava/junit/localtests/deamontest/DeamonTest.java b/workspace/popjava/test/ch/icosys/popjava/junit/localtests/deamontest/DeamonTest.java index 7f920e78..1ea7ea74 100644 --- a/workspace/popjava/test/ch/icosys/popjava/junit/localtests/deamontest/DeamonTest.java +++ b/workspace/popjava/test/ch/icosys/popjava/junit/localtests/deamontest/DeamonTest.java @@ -2,8 +2,10 @@ import static org.junit.Assert.*; +import java.io.File; import java.io.IOException; +import org.junit.Assume; import org.junit.Test; import ch.icosys.popjava.core.PopJava; @@ -20,6 +22,7 @@ public class DeamonTest { */ @Test public void testDynamicCreationFail() { + Assume.assumeTrue(new File(POPJavaDeamon.BACKUP_JAR).exists()); POPSystem.initialize(); try { @@ -33,6 +36,7 @@ public void testDynamicCreationFail() { } private static POPJavaDeamon startDeamon(String password) throws InterruptedException { + Assume.assumeTrue(new File(POPJavaDeamon.BACKUP_JAR).exists()); final POPJavaDeamon deamon = new POPJavaDeamon(password); Thread thread = new Thread(new Runnable() { @@ -51,6 +55,7 @@ public void run() { @Test public void testSuccess() throws IOException, InterruptedException { + Assume.assumeTrue(new File(POPJavaDeamon.BACKUP_JAR).exists()); POPSystem.initialize(); POPJavaDeamon deamon = startDeamon(""); @@ -65,6 +70,7 @@ public void testSuccess() throws IOException, InterruptedException { @Test public void testDynamicCreation() throws IOException, InterruptedException { + Assume.assumeTrue(new File(POPJavaDeamon.BACKUP_JAR).exists()); POPSystem.initialize(); POPJavaDeamon deamon = startDeamon(""); TestClass test = PopJava.newActive(this, TestClass.class, ConnectionType.DAEMON, ""); @@ -79,6 +85,7 @@ public void testDynamicCreation() throws IOException, InterruptedException { @Test public void testDynamicCreationPassword() throws IOException, InterruptedException { + Assume.assumeTrue(new File(POPJavaDeamon.BACKUP_JAR).exists()); POPSystem.initialize(); String password = "12345"; POPJavaDeamon deamon = startDeamon(password); @@ -93,6 +100,7 @@ public void testDynamicCreationPassword() throws IOException, InterruptedExcepti @Test public void testDynamicCreationPasswordMissmatch() throws IOException, InterruptedException { + Assume.assumeTrue(new File(POPJavaDeamon.BACKUP_JAR).exists()); POPSystem.initialize(); String password = "12345"; POPJavaDeamon deamon = startDeamon(password); @@ -111,6 +119,7 @@ public void testDynamicCreationPasswordMissmatch() throws IOException, Interrupt @Test public void testMultiObjectCreation() throws InterruptedException, IOException { + Assume.assumeTrue(new File(POPJavaDeamon.BACKUP_JAR).exists()); POPSystem.initialize(); String password = "12345"; POPJavaDeamon deamon = startDeamon(password); diff --git a/workspace/popjava/test/ch/icosys/popjava/junit/system/POPSystemTest.java b/workspace/popjava/test/ch/icosys/popjava/junit/system/POPSystemTest.java index e019acda..978fd36c 100644 --- a/workspace/popjava/test/ch/icosys/popjava/junit/system/POPSystemTest.java +++ b/workspace/popjava/test/ch/icosys/popjava/junit/system/POPSystemTest.java @@ -12,6 +12,7 @@ import ch.icosys.popjava.core.serviceadapter.POPAppService; import ch.icosys.popjava.core.system.POPJavaConfiguration; import ch.icosys.popjava.core.system.POPSystem; +import ch.icosys.popjava.core.util.SystemUtil; import ch.icosys.popjava.core.util.Util; import ch.icosys.popjava.core.util.Util.OSType; @@ -69,4 +70,14 @@ public void testParameterCleaning() { * Util.removeStringFromList(argvList, "-appservicecontact="); */ } + + @Test + public void testSubnetID() { + assertTrue(SystemUtil.isHostInPrivateSubnet("10.0.0.1")); + assertFalse(SystemUtil.isHostInPrivateSubnet("1.2.3.4")); + assertTrue(SystemUtil.isHostInPrivateSubnet("192.168.10.1")); + assertTrue(SystemUtil.isHostInPrivateSubnet("172.16.10.1")); + assertFalse(SystemUtil.isHostInPrivateSubnet("172.3.10.1")); + assertTrue(SystemUtil.isHostInPrivateSubnet("172.31.10.1")); + } }