summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorAdam Ierymenko <[email protected]>2023-03-07 16:50:34 -0500
committerGitHub <[email protected]>2023-03-07 16:50:34 -0500
commit1c5897895bb0f2c8b054dfc2465c9cc5548fb954 (patch)
tree8ac0ecb8013d09a304549ea683c442991cbcff02 /java
parentdea47f601d458ff810c7949f35bc06f6ba6df170 (diff)
1.10.4 merge into main (#1893)
* add note about forceTcpRelay * Create a sample systemd unit for tcp proxy * set gitattributes for rust & cargo so hashes dont conflict on Windows * Revert "set gitattributes for rust & cargo so hashes dont conflict on Windows" This reverts commit 032dc5c108195f6bbc2e224f00da5b785df4b7f9. * Turn off autocrlf for rust source Doesn't appear to play nice well when it comes to git and vendored cargo package hashes * Fix #1883 (#1886) Still unknown as to why, but the call to `nc->GetProperties()` can fail when setting a friendly name on the Windows virtual ethernet adapter. Ensure that `ncp` is not null before continuing and accessing the device GUID. * Don't vendor packages for zeroidc (#1885) * Added docker environment way to join networks (#1871) * add StringUtils * fix headers use recommended headers and remove unused headers * move extern "C" only JNI functions need to be exported * cleanup * fix ANDROID-50: RESULT_ERROR_BAD_PARAMETER typo * fix typo in log message * fix typos in JNI method signatures * fix typo * fix ANDROID-51: fieldName is uninitialized * fix ANDROID-35: memory leak * fix missing DeleteLocalRef in loops * update to use unique error codes * add GETENV macro * add LOG_TAG defines * ANDROID-48: add ZT_jnicache.cpp * ANDROID-48: use ZT_jnicache.cpp and remove ZT_jnilookup.cpp and ZT_jniarray.cpp * add Event.fromInt * add PeerRole.fromInt * add ResultCode.fromInt * fix ANDROID-36: issues with ResultCode * add VirtualNetworkConfigOperation.fromInt * fix ANDROID-40: VirtualNetworkConfigOperation out-of-sync with ZT_VirtualNetworkConfigOperation enum * add VirtualNetworkStatus.fromInt * fix ANDROID-37: VirtualNetworkStatus out-of-sync with ZT_VirtualNetworkStatus enum * add VirtualNetworkType.fromInt * make NodeStatus a plain data class * fix ANDROID-52: synchronization bug with nodeMap * Node init work: separate Node construction and init * add Node.toString * make PeerPhysicalPath a plain data class * remove unused PeerPhysicalPath.fixed * add array functions * make Peer a plain data class * make Version a plain data class * fix ANDROID-42: copy/paste error * fix ANDROID-49: VirtualNetworkConfig.equals is wrong * reimplement VirtualNetworkConfig.equals * reimplement VirtualNetworkConfig.compareTo * add VirtualNetworkConfig.hashCode * make VirtualNetworkConfig a plain data class * remove unused VirtualNetworkConfig.enabled * reimplement VirtualNetworkDNS.equals * add VirtualNetworkDNS.hashCode * make VirtualNetworkDNS a plain data class * reimplement VirtualNetworkRoute.equals * reimplement VirtualNetworkRoute.compareTo * reimplement VirtualNetworkRoute.toString * add VirtualNetworkRoute.hashCode * make VirtualNetworkRoute a plain data class * add isSocketAddressEmpty * add addressPort * add fromSocketAddressObject * invert logic in a couple of places and return early * newInetAddress and newInetSocketAddress work allow newInetSocketAddress to return NULL if given empty address * fix ANDROID-38: stack corruption in onSendPacketRequested * use GETENV macro * JniRef work JniRef does not use callbacks struct, so remove fix NewGlobalRef / DeleteGlobalRef mismatch * use PRId64 macros * switch statement work * comments and logging * Modifier 'public' is redundant for interface members * NodeException can be made a checked Exception * 'NodeException' does not define a 'serialVersionUID' field * 'finalize()' should not be overridden this is fine to do because ZeroTierOneService calls close() when it is done * error handling, error reporting, asserts, logging * simplify loadLibrary * rename Node.networks -> Node.networkConfigs * Windows file permissions fix (#1887) * Allow macOS interfaces to use multiple IP addresses (#1879) Co-authored-by: Sean OMeara <[email protected]> Co-authored-by: Grant Limberg <[email protected]> * Fix condition where full HELLOs might not be sent when necessary (#1877) Co-authored-by: Grant Limberg <[email protected]> * 1.10.4 version bumps * Add security policy to repo (#1889) * [+] add e2k64 arch (#1890) * temp fix for ANDROID-56: crash inside newNetworkConfig from too many args * 1.10.4 release notes --------- Co-authored-by: travis laduke <[email protected]> Co-authored-by: Grant Limberg <[email protected]> Co-authored-by: Grant Limberg <[email protected]> Co-authored-by: Leonardo Amaral <[email protected]> Co-authored-by: Brenton Bostick <[email protected]> Co-authored-by: Sean OMeara <[email protected]> Co-authored-by: Joseph Henry <[email protected]> Co-authored-by: Roman Peshkichev <[email protected]>
Diffstat (limited to 'java')
-rw-r--r--java/jni/ZT_jniarray.cpp112
-rw-r--r--java/jni/ZT_jniarray.h60
-rw-r--r--java/jni/ZT_jnicache.cpp244
-rw-r--r--java/jni/ZT_jnicache.h92
-rw-r--r--java/jni/ZT_jnilookup.cpp158
-rw-r--r--java/jni/ZT_jnilookup.h54
-rw-r--r--java/jni/ZT_jniutils.cpp1060
-rw-r--r--java/jni/ZT_jniutils.h108
-rw-r--r--java/jni/com_zerotierone_sdk_Node.cpp1302
-rw-r--r--java/jni/com_zerotierone_sdk_Node.h16
-rw-r--r--java/src/com/zerotier/sdk/DataStoreGetListener.java3
-rw-r--r--java/src/com/zerotier/sdk/DataStorePutListener.java5
-rw-r--r--java/src/com/zerotier/sdk/Event.java70
-rw-r--r--java/src/com/zerotier/sdk/EventListener.java8
-rw-r--r--java/src/com/zerotier/sdk/NativeUtils.java93
-rw-r--r--java/src/com/zerotier/sdk/Node.java131
-rw-r--r--java/src/com/zerotier/sdk/NodeException.java7
-rw-r--r--java/src/com/zerotier/sdk/NodeStatus.java59
-rw-r--r--java/src/com/zerotier/sdk/PacketSender.java5
-rw-r--r--java/src/com/zerotier/sdk/PathChecker.java2
-rw-r--r--java/src/com/zerotier/sdk/Peer.java62
-rw-r--r--java/src/com/zerotier/sdk/PeerPhysicalPath.java52
-rw-r--r--java/src/com/zerotier/sdk/PeerRole.java34
-rw-r--r--java/src/com/zerotier/sdk/ResultCode.java48
-rw-r--r--java/src/com/zerotier/sdk/Version.java31
-rw-r--r--java/src/com/zerotier/sdk/VirtualNetworkConfig.java327
-rw-r--r--java/src/com/zerotier/sdk/VirtualNetworkConfigListener.java8
-rw-r--r--java/src/com/zerotier/sdk/VirtualNetworkConfigOperation.java37
-rw-r--r--java/src/com/zerotier/sdk/VirtualNetworkDNS.java63
-rw-r--r--java/src/com/zerotier/sdk/VirtualNetworkFrameListener.java7
-rw-r--r--java/src/com/zerotier/sdk/VirtualNetworkRoute.java145
-rw-r--r--java/src/com/zerotier/sdk/VirtualNetworkStatus.java57
-rw-r--r--java/src/com/zerotier/sdk/VirtualNetworkType.java29
-rw-r--r--java/src/com/zerotier/sdk/util/StringUtils.java52
-rw-r--r--java/test/com/zerotier/sdk/util/StringUtilsTest.java73
35 files changed, 2256 insertions, 2358 deletions
diff --git a/java/jni/ZT_jniarray.cpp b/java/jni/ZT_jniarray.cpp
deleted file mode 100644
index a1cae76e..00000000
--- a/java/jni/ZT_jniarray.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// Created by Grant Limberg on 10/21/20.
-//
-
-#include "ZT_jniarray.h"
-#include <vector>
-#include <string>
-#include <cassert>
-
-jclass java_util_ArrayList;
-jmethodID java_util_ArrayList_;
-jmethodID java_util_ArrayList_size;
-jmethodID java_util_ArrayList_get;
-jmethodID java_util_ArrayList_add;
-
-void InitListJNI(JNIEnv* env) {
- java_util_ArrayList = static_cast<jclass>(env->NewGlobalRef(env->FindClass("java/util/ArrayList")));
- java_util_ArrayList_ = env->GetMethodID(java_util_ArrayList, "<init>", "(I)V");
- java_util_ArrayList_size = env->GetMethodID (java_util_ArrayList, "size", "()I");
- java_util_ArrayList_get = env->GetMethodID(java_util_ArrayList, "get", "(I)Ljava/lang/Object;");
- java_util_ArrayList_add = env->GetMethodID(java_util_ArrayList, "add", "(Ljava/lang/Object;)Z");
-}
-
-jclass ListJNI::getListClass(JNIEnv* env) {
- jclass jclazz = env->FindClass("java/util/List");
- assert(jclazz != nullptr);
- return jclazz;
-}
-
-jclass ListJNI::getArrayListClass(JNIEnv* env) {
- jclass jclazz = env->FindClass("java/util/ArrayList");
- assert(jclazz != nullptr);
- return jclazz;
-}
-
-jclass ListJNI::getIteratorClass(JNIEnv* env) {
- jclass jclazz = env->FindClass("java/util/Iterator");
- assert(jclazz != nullptr);
- return jclazz;
-}
-
-jmethodID ListJNI::getIteratorMethod(JNIEnv* env) {
- static jmethodID mid = env->GetMethodID(
- getListClass(env), "iterator", "()Ljava/util/Iterator;");
- assert(mid != nullptr);
- return mid;
-}
-
-jmethodID ListJNI::getHasNextMethod(JNIEnv* env) {
- static jmethodID mid = env->GetMethodID(
- getIteratorClass(env), "hasNext", "()Z");
- assert(mid != nullptr);
- return mid;
-}
-
-jmethodID ListJNI::getNextMethod(JNIEnv* env) {
- static jmethodID mid = env->GetMethodID(
- getIteratorClass(env), "next", "()Ljava/lang/Object;");
- assert(mid != nullptr);
- return mid;
-}
-
-jmethodID ListJNI::getArrayListConstructorMethodId(JNIEnv* env, jclass jclazz) {
- static jmethodID mid = env->GetMethodID(
- jclazz, "<init>", "(I)V");
- assert(mid != nullptr);
- return mid;
-}
-
-jmethodID ListJNI::getListAddMethodId(JNIEnv* env) {
- static jmethodID mid = env->GetMethodID(
- getListClass(env), "add", "(Ljava/lang/Object;)Z");
- assert(mid != nullptr);
- return mid;
-}
-
-jclass ByteJNI::getByteClass(JNIEnv* env) {
- jclass jclazz = env->FindClass("java/lang/Byte");
- assert(jclazz != nullptr);
- return jclazz;
-}
-
-jmethodID ByteJNI::getByteValueMethod(JNIEnv* env) {
- static jmethodID mid = env->GetMethodID(
- getByteClass(env), "byteValue", "()B");
- assert(mid != nullptr);
- return mid;
-}
-
-jobject cppToJava(JNIEnv* env, std::vector<std::string> vector) {
- jobject result = env->NewObject(java_util_ArrayList, java_util_ArrayList_, vector.size());
- for (std::string s: vector) {
- jstring element = env->NewStringUTF(s.c_str());
- env->CallBooleanMethod(result, java_util_ArrayList_add, element);
- env->DeleteLocalRef(element);
- }
- return result;
-}
-
-std::vector<std::string> javaToCpp(JNIEnv* env, jobject arrayList) {
- jint len = env->CallIntMethod(arrayList, java_util_ArrayList_size);
- std::vector<std::string> result;
- result.reserve(len);
- for (jint i=0; i<len; i++) {
- jstring element = static_cast<jstring>(env->CallObjectMethod(arrayList, java_util_ArrayList_get, i));
- const char* pchars = env->GetStringUTFChars(element, nullptr);
- result.emplace_back(pchars);
- env->ReleaseStringUTFChars(element, pchars);
- env->DeleteLocalRef(element);
- }
- return result;
-}
diff --git a/java/jni/ZT_jniarray.h b/java/jni/ZT_jniarray.h
deleted file mode 100644
index d93c87b9..00000000
--- a/java/jni/ZT_jniarray.h
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// Created by Grant Limberg on 10/21/20.
-//
-
-#ifndef ZEROTIERANDROID_ZT_JNIARRAY_H
-#define ZEROTIERANDROID_ZT_JNIARRAY_H
-
-#include <jni.h>
-#include <vector>
-#include <string>
-
-extern jclass java_util_ArrayList;
-extern jmethodID java_util_ArrayList_;
-extern jmethodID java_util_ArrayList_size;
-extern jmethodID java_util_ArrayList_get;
-extern jmethodID java_util_ArrayList_add;
-
-void InitListJNI(JNIEnv* env);
-
-class ListJNI {
-public:
- // Get the java class id of java.util.List.
- static jclass getListClass(JNIEnv* env);
-
- // Get the java class id of java.util.ArrayList.
- static jclass getArrayListClass(JNIEnv* env);
-
- // Get the java class id of java.util.Iterator.
- static jclass getIteratorClass(JNIEnv* env);
-
- // Get the java method id of java.util.List.iterator().
- static jmethodID getIteratorMethod(JNIEnv* env);
-
- // Get the java method id of java.util.Iterator.hasNext().
- static jmethodID getHasNextMethod(JNIEnv* env);
-
- // Get the java method id of java.util.Iterator.next().
- static jmethodID getNextMethod(JNIEnv* env);
-
- // Get the java method id of arrayList constructor.
- static jmethodID getArrayListConstructorMethodId(JNIEnv* env, jclass jclazz);
-
- // Get the java method id of java.util.List.add().
- static jmethodID getListAddMethodId(JNIEnv* env);
-};
-
-class ByteJNI {
-public:
- // Get the java class id of java.lang.Byte.
- static jclass getByteClass(JNIEnv* env);
-
- // Get the java method id of java.lang.Byte.byteValue.
- static jmethodID getByteValueMethod(JNIEnv* env);
-};
-
-jobject cppToJava(JNIEnv* env, std::vector<std::string> vector);
-
-std::vector<std::string> javaToCpp(JNIEnv* env, jobject arrayList);
-
-#endif //ZEROTIERANDROID_ZT_JNIARRAY_H
diff --git a/java/jni/ZT_jnicache.cpp b/java/jni/ZT_jnicache.cpp
new file mode 100644
index 00000000..68cacbd7
--- /dev/null
+++ b/java/jni/ZT_jnicache.cpp
@@ -0,0 +1,244 @@
+//
+// Created by Brenton Bostick on 1/18/23.
+//
+
+#include "ZT_jnicache.h"
+
+#include "ZT_jniutils.h"
+
+#include <cassert>
+
+#define LOG_TAG "Cache"
+
+#define EXCEPTIONANDNULLCHECK(var) \
+ do { \
+ if (env->ExceptionCheck()) { \
+ assert(false && "Exception"); \
+ } \
+ if ((var) == NULL) { \
+ assert(false && #var " is NULL"); \
+ } \
+ } while (false)
+
+#define SETCLASS(classVar, classNameString) \
+ do { \
+ jclass classVar ## _local = env->FindClass(classNameString); \
+ EXCEPTIONANDNULLCHECK(classVar ## _local); \
+ classVar = reinterpret_cast<jclass>(env->NewGlobalRef(classVar ## _local)); \
+ EXCEPTIONANDNULLCHECK(classVar); \
+ env->DeleteLocalRef(classVar ## _local); \
+ } while (false)
+
+#define SETOBJECT(objectVar, code) \
+ do { \
+ jobject objectVar ## _local = code; \
+ EXCEPTIONANDNULLCHECK(objectVar ## _local); \
+ objectVar = env->NewGlobalRef(objectVar ## _local); \
+ EXCEPTIONANDNULLCHECK(objectVar); \
+ env->DeleteLocalRef(objectVar ## _local); \
+ } while (false)
+
+
+//
+// Classes
+//
+
+jclass ArrayList_class;
+jclass DataStoreGetListener_class;
+jclass DataStorePutListener_class;
+jclass EventListener_class;
+jclass Event_class;
+jclass Inet4Address_class;
+jclass Inet6Address_class;
+jclass InetAddress_class;
+jclass InetSocketAddress_class;
+jclass NodeStatus_class;
+jclass Node_class;
+jclass PacketSender_class;
+jclass PathChecker_class;
+jclass PeerPhysicalPath_class;
+jclass PeerRole_class;
+jclass Peer_class;
+jclass ResultCode_class;
+jclass Version_class;
+jclass VirtualNetworkConfigListener_class;
+jclass VirtualNetworkConfigOperation_class;
+jclass VirtualNetworkConfig_class;
+jclass VirtualNetworkDNS_class;
+jclass VirtualNetworkFrameListener_class;
+jclass VirtualNetworkRoute_class;
+jclass VirtualNetworkStatus_class;
+jclass VirtualNetworkType_class;
+
+//
+// Instance methods
+//
+
+jmethodID ArrayList_add_method;
+jmethodID ArrayList_ctor;
+jmethodID DataStoreGetListener_onDataStoreGet_method;
+jmethodID DataStorePutListener_onDataStorePut_method;
+jmethodID DataStorePutListener_onDelete_method;
+jmethodID EventListener_onEvent_method;
+jmethodID EventListener_onTrace_method;
+jmethodID InetAddress_getAddress_method;
+jmethodID InetSocketAddress_ctor;
+jmethodID InetSocketAddress_getAddress_method;
+jmethodID InetSocketAddress_getPort_method;
+jmethodID NodeStatus_ctor;
+jmethodID PacketSender_onSendPacketRequested_method;
+jmethodID PathChecker_onPathCheck_method;
+jmethodID PathChecker_onPathLookup_method;
+jmethodID PeerPhysicalPath_ctor;
+jmethodID Peer_ctor;
+jmethodID Version_ctor;
+jmethodID VirtualNetworkConfigListener_onNetworkConfigurationUpdated_method;
+jmethodID VirtualNetworkConfig_ctor;
+jmethodID VirtualNetworkDNS_ctor;
+jmethodID VirtualNetworkFrameListener_onVirtualNetworkFrame_method;
+jmethodID VirtualNetworkRoute_ctor;
+
+//
+// Static methods
+//
+
+jmethodID Event_fromInt_method;
+jmethodID InetAddress_getByAddress_method;
+jmethodID PeerRole_fromInt_method;
+jmethodID ResultCode_fromInt_method;
+jmethodID VirtualNetworkConfigOperation_fromInt_method;
+jmethodID VirtualNetworkStatus_fromInt_method;
+jmethodID VirtualNetworkType_fromInt_method;
+
+//
+// Enums
+//
+
+jobject ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+jobject ResultCode_RESULT_OK_enum;
+
+void setupJNICache(JavaVM *vm) {
+
+ JNIEnv *env;
+ GETENV(env, vm);
+
+ //
+ // Classes
+ //
+
+ SETCLASS(ArrayList_class, "java/util/ArrayList");
+ SETCLASS(DataStoreGetListener_class, "com/zerotier/sdk/DataStoreGetListener");
+ SETCLASS(DataStorePutListener_class, "com/zerotier/sdk/DataStorePutListener");
+ SETCLASS(EventListener_class, "com/zerotier/sdk/EventListener");
+ SETCLASS(Event_class, "com/zerotier/sdk/Event");
+ SETCLASS(Inet4Address_class, "java/net/Inet4Address");
+ SETCLASS(Inet6Address_class, "java/net/Inet6Address");
+ SETCLASS(InetAddress_class, "java/net/InetAddress");
+ SETCLASS(InetSocketAddress_class, "java/net/InetSocketAddress");
+ SETCLASS(NodeStatus_class, "com/zerotier/sdk/NodeStatus");
+ SETCLASS(Node_class, "com/zerotier/sdk/Node");
+ SETCLASS(PacketSender_class, "com/zerotier/sdk/PacketSender");
+ SETCLASS(PathChecker_class, "com/zerotier/sdk/PathChecker");
+ SETCLASS(PeerPhysicalPath_class, "com/zerotier/sdk/PeerPhysicalPath");
+ SETCLASS(PeerRole_class, "com/zerotier/sdk/PeerRole");
+ SETCLASS(Peer_class, "com/zerotier/sdk/Peer");
+ SETCLASS(ResultCode_class, "com/zerotier/sdk/ResultCode");
+ SETCLASS(Version_class, "com/zerotier/sdk/Version");
+ SETCLASS(VirtualNetworkConfigListener_class, "com/zerotier/sdk/VirtualNetworkConfigListener");
+ SETCLASS(VirtualNetworkConfigOperation_class, "com/zerotier/sdk/VirtualNetworkConfigOperation");
+ SETCLASS(VirtualNetworkConfig_class, "com/zerotier/sdk/VirtualNetworkConfig");
+ SETCLASS(VirtualNetworkDNS_class, "com/zerotier/sdk/VirtualNetworkDNS");
+ SETCLASS(VirtualNetworkFrameListener_class, "com/zerotier/sdk/VirtualNetworkFrameListener");
+ SETCLASS(VirtualNetworkRoute_class, "com/zerotier/sdk/VirtualNetworkRoute");
+ SETCLASS(VirtualNetworkStatus_class, "com/zerotier/sdk/VirtualNetworkStatus");
+ SETCLASS(VirtualNetworkType_class, "com/zerotier/sdk/VirtualNetworkType");
+
+ //
+ // Instance methods
+ //
+
+ EXCEPTIONANDNULLCHECK(ArrayList_add_method = env->GetMethodID(ArrayList_class, "add", "(Ljava/lang/Object;)Z"));
+ EXCEPTIONANDNULLCHECK(ArrayList_ctor = env->GetMethodID(ArrayList_class, "<init>", "(I)V"));
+ EXCEPTIONANDNULLCHECK(DataStoreGetListener_onDataStoreGet_method = env->GetMethodID(DataStoreGetListener_class, "onDataStoreGet", "(Ljava/lang/String;[B)J"));
+ EXCEPTIONANDNULLCHECK(DataStorePutListener_onDataStorePut_method = env->GetMethodID(DataStorePutListener_class, "onDataStorePut", "(Ljava/lang/String;[BZ)I"));
+ EXCEPTIONANDNULLCHECK(DataStorePutListener_onDelete_method = env->GetMethodID(DataStorePutListener_class, "onDelete", "(Ljava/lang/String;)I"));
+ EXCEPTIONANDNULLCHECK(EventListener_onEvent_method = env->GetMethodID(EventListener_class, "onEvent", "(Lcom/zerotier/sdk/Event;)V"));
+ EXCEPTIONANDNULLCHECK(EventListener_onTrace_method = env->GetMethodID(EventListener_class, "onTrace", "(Ljava/lang/String;)V"));
+ EXCEPTIONANDNULLCHECK(InetAddress_getAddress_method = env->GetMethodID(InetAddress_class, "getAddress", "()[B"));
+ EXCEPTIONANDNULLCHECK(InetSocketAddress_ctor = env->GetMethodID(InetSocketAddress_class, "<init>", "(Ljava/net/InetAddress;I)V"));
+ EXCEPTIONANDNULLCHECK(InetSocketAddress_getAddress_method = env->GetMethodID(InetSocketAddress_class, "getAddress", "()Ljava/net/InetAddress;"));
+ EXCEPTIONANDNULLCHECK(InetSocketAddress_getPort_method = env->GetMethodID(InetSocketAddress_class, "getPort", "()I"));
+ EXCEPTIONANDNULLCHECK(NodeStatus_ctor = env->GetMethodID(NodeStatus_class, "<init>", "(JLjava/lang/String;Ljava/lang/String;Z)V"));
+ EXCEPTIONANDNULLCHECK(PacketSender_onSendPacketRequested_method = env->GetMethodID(PacketSender_class, "onSendPacketRequested", "(JLjava/net/InetSocketAddress;[BI)I"));
+ EXCEPTIONANDNULLCHECK(PathChecker_onPathCheck_method = env->GetMethodID(PathChecker_class, "onPathCheck", "(JJLjava/net/InetSocketAddress;)Z"));
+ EXCEPTIONANDNULLCHECK(PathChecker_onPathLookup_method = env->GetMethodID(PathChecker_class, "onPathLookup", "(JI)Ljava/net/InetSocketAddress;"));
+ EXCEPTIONANDNULLCHECK(PeerPhysicalPath_ctor = env->GetMethodID(PeerPhysicalPath_class, "<init>", "(Ljava/net/InetSocketAddress;JJZ)V"));
+ EXCEPTIONANDNULLCHECK(Peer_ctor = env->GetMethodID(Peer_class, "<init>", "(JIIIILcom/zerotier/sdk/PeerRole;[Lcom/zerotier/sdk/PeerPhysicalPath;)V"));
+ EXCEPTIONANDNULLCHECK(Version_ctor = env->GetMethodID(Version_class, "<init>", "(III)V"));
+ EXCEPTIONANDNULLCHECK(VirtualNetworkConfigListener_onNetworkConfigurationUpdated_method = env->GetMethodID(VirtualNetworkConfigListener_class, "onNetworkConfigurationUpdated", "(JLcom/zerotier/sdk/VirtualNetworkConfigOperation;Lcom/zerotier/sdk/VirtualNetworkConfig;)I"));
+
+
+ //
+ // ANDROID-56: temporarily remove parameters to prevent crashing
+ //
+// EXCEPTIONANDNULLCHECK(VirtualNetworkConfig_ctor = env->GetMethodID(VirtualNetworkConfig_class, "<init>", "(JJLjava/lang/String;Lcom/zerotier/sdk/VirtualNetworkStatus;Lcom/zerotier/sdk/VirtualNetworkType;IZZZIJ[Ljava/net/InetSocketAddress;[Lcom/zerotier/sdk/VirtualNetworkRoute;Lcom/zerotier/sdk/VirtualNetworkDNS;)V"));
+ EXCEPTIONANDNULLCHECK(VirtualNetworkConfig_ctor = env->GetMethodID(VirtualNetworkConfig_class, "<init>", "(JJLjava/lang/String;Lcom/zerotier/sdk/VirtualNetworkStatus;Lcom/zerotier/sdk/VirtualNetworkType;IZZZ[Ljava/net/InetSocketAddress;[Lcom/zerotier/sdk/VirtualNetworkRoute;Lcom/zerotier/sdk/VirtualNetworkDNS;)V"));
+
+
+ EXCEPTIONANDNULLCHECK(VirtualNetworkDNS_ctor = env->GetMethodID(VirtualNetworkDNS_class, "<init>", "(Ljava/lang/String;Ljava/util/ArrayList;)V"));
+ EXCEPTIONANDNULLCHECK(VirtualNetworkFrameListener_onVirtualNetworkFrame_method = env->GetMethodID(VirtualNetworkFrameListener_class, "onVirtualNetworkFrame", "(JJJJJ[B)V"));
+ EXCEPTIONANDNULLCHECK(VirtualNetworkRoute_ctor = env->GetMethodID(VirtualNetworkRoute_class, "<init>", "(Ljava/net/InetSocketAddress;Ljava/net/InetSocketAddress;II)V"));
+
+ //
+ // Static methods
+ //
+
+ EXCEPTIONANDNULLCHECK(Event_fromInt_method = env->GetStaticMethodID(Event_class, "fromInt", "(I)Lcom/zerotier/sdk/Event;"));
+ EXCEPTIONANDNULLCHECK(InetAddress_getByAddress_method = env->GetStaticMethodID(InetAddress_class, "getByAddress", "([B)Ljava/net/InetAddress;"));
+ EXCEPTIONANDNULLCHECK(PeerRole_fromInt_method = env->GetStaticMethodID(PeerRole_class, "fromInt", "(I)Lcom/zerotier/sdk/PeerRole;"));
+ EXCEPTIONANDNULLCHECK(ResultCode_fromInt_method = env->GetStaticMethodID(ResultCode_class, "fromInt", "(I)Lcom/zerotier/sdk/ResultCode;"));
+ EXCEPTIONANDNULLCHECK(VirtualNetworkConfigOperation_fromInt_method = env->GetStaticMethodID(VirtualNetworkConfigOperation_class, "fromInt", "(I)Lcom/zerotier/sdk/VirtualNetworkConfigOperation;"));
+ EXCEPTIONANDNULLCHECK(VirtualNetworkStatus_fromInt_method = env->GetStaticMethodID(VirtualNetworkStatus_class, "fromInt", "(I)Lcom/zerotier/sdk/VirtualNetworkStatus;"));
+ EXCEPTIONANDNULLCHECK(VirtualNetworkType_fromInt_method = env->GetStaticMethodID(VirtualNetworkType_class, "fromInt", "(I)Lcom/zerotier/sdk/VirtualNetworkType;"));
+
+ //
+ // Enums
+ //
+
+ SETOBJECT(ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum, createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL));
+ SETOBJECT(ResultCode_RESULT_OK_enum, createResultObject(env, ZT_RESULT_OK));
+}
+
+void teardownJNICache(JavaVM *vm) {
+
+ JNIEnv *env;
+ GETENV(env, vm);
+
+ env->DeleteGlobalRef(ArrayList_class);
+ env->DeleteGlobalRef(DataStoreGetListener_class);
+ env->DeleteGlobalRef(DataStorePutListener_class);
+ env->DeleteGlobalRef(EventListener_class);
+ env->DeleteGlobalRef(Event_class);
+ env->DeleteGlobalRef(InetAddress_class);
+ env->DeleteGlobalRef(InetSocketAddress_class);
+ env->DeleteGlobalRef(NodeStatus_class);
+ env->DeleteGlobalRef(Node_class);
+ env->DeleteGlobalRef(PacketSender_class);
+ env->DeleteGlobalRef(PathChecker_class);
+ env->DeleteGlobalRef(PeerPhysicalPath_class);
+ env->DeleteGlobalRef(PeerRole_class);
+ env->DeleteGlobalRef(Peer_class);
+ env->DeleteGlobalRef(ResultCode_class);
+ env->DeleteGlobalRef(Version_class);
+ env->DeleteGlobalRef(VirtualNetworkConfigListener_class);
+ env->DeleteGlobalRef(VirtualNetworkConfigOperation_class);
+ env->DeleteGlobalRef(VirtualNetworkConfig_class);
+ env->DeleteGlobalRef(VirtualNetworkDNS_class);
+ env->DeleteGlobalRef(VirtualNetworkFrameListener_class);
+ env->DeleteGlobalRef(VirtualNetworkRoute_class);
+ env->DeleteGlobalRef(VirtualNetworkStatus_class);
+ env->DeleteGlobalRef(VirtualNetworkType_class);
+
+ env->DeleteGlobalRef(ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum);
+ env->DeleteGlobalRef(ResultCode_RESULT_OK_enum);
+}
diff --git a/java/jni/ZT_jnicache.h b/java/jni/ZT_jnicache.h
new file mode 100644
index 00000000..c5cc9cb2
--- /dev/null
+++ b/java/jni/ZT_jnicache.h
@@ -0,0 +1,92 @@
+//
+// Created by Brenton Bostick on 1/18/23.
+//
+
+#ifndef ZEROTIERANDROID_JNICACHE_H
+#define ZEROTIERANDROID_JNICACHE_H
+
+#include <jni.h>
+
+
+//
+// Classes
+//
+
+extern jclass ArrayList_class;
+extern jclass DataStoreGetListener_class;
+extern jclass DataStorePutListener_class;
+extern jclass EventListener_class;
+extern jclass Event_class;
+extern jclass Inet4Address_class;
+extern jclass Inet6Address_class;
+extern jclass InetAddress_class;
+extern jclass InetSocketAddress_class;
+extern jclass NodeStatus_class;
+extern jclass Node_class;
+extern jclass PacketSender_class;
+extern jclass PathChecker_class;
+extern jclass PeerPhysicalPath_class;
+extern jclass PeerRole_class;
+extern jclass Peer_class;
+extern jclass ResultCode_class;
+extern jclass Version_class;
+extern jclass VirtualNetworkConfigListener_class;
+extern jclass VirtualNetworkConfigOperation_class;
+extern jclass VirtualNetworkConfig_class;
+extern jclass VirtualNetworkDNS_class;
+extern jclass VirtualNetworkFrameListener_class;
+extern jclass VirtualNetworkRoute_class;
+extern jclass VirtualNetworkStatus_class;
+extern jclass VirtualNetworkType_class;
+
+//
+// Instance methods
+//
+
+extern jmethodID ArrayList_add_method;
+extern jmethodID ArrayList_ctor;
+extern jmethodID DataStoreGetListener_onDataStoreGet_method;
+extern jmethodID DataStorePutListener_onDataStorePut_method;
+extern jmethodID DataStorePutListener_onDelete_method;
+extern jmethodID EventListener_onEvent_method;
+extern jmethodID EventListener_onTrace_method;
+extern jmethodID InetAddress_getAddress_method;
+extern jmethodID InetSocketAddress_ctor;
+extern jmethodID InetSocketAddress_getAddress_method;
+extern jmethodID InetSocketAddress_getPort_method;
+extern jmethodID NodeStatus_ctor;
+extern jmethodID PacketSender_onSendPacketRequested_method;
+extern jmethodID PathChecker_onPathCheck_method;
+extern jmethodID PathChecker_onPathLookup_method;
+extern jmethodID PeerPhysicalPath_ctor;
+extern jmethodID Peer_ctor;
+extern jmethodID Version_ctor;
+extern jmethodID VirtualNetworkConfigListener_onNetworkConfigurationUpdated_method;
+extern jmethodID VirtualNetworkConfig_ctor;
+extern jmethodID VirtualNetworkDNS_ctor;
+extern jmethodID VirtualNetworkFrameListener_onVirtualNetworkFrame_method;
+extern jmethodID VirtualNetworkRoute_ctor;
+
+//
+// Static methods
+//
+
+extern jmethodID Event_fromInt_method;
+extern jmethodID InetAddress_getByAddress_method;
+extern jmethodID PeerRole_fromInt_method;
+extern jmethodID ResultCode_fromInt_method;
+extern jmethodID VirtualNetworkConfigOperation_fromInt_method;
+extern jmethodID VirtualNetworkStatus_fromInt_method;
+extern jmethodID VirtualNetworkType_fromInt_method;
+
+//
+// Enums
+//
+
+extern jobject ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+extern jobject ResultCode_RESULT_OK_enum;
+
+void setupJNICache(JavaVM *vm);
+void teardownJNICache(JavaVM *vm);
+
+#endif // ZEROTIERANDROID_JNICACHE_H
diff --git a/java/jni/ZT_jnilookup.cpp b/java/jni/ZT_jnilookup.cpp
deleted file mode 100644
index 4d867a35..00000000
--- a/java/jni/ZT_jnilookup.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * 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/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include "ZT_jnilookup.h"
-#include "ZT_jniutils.h"
-
-JniLookup::JniLookup()
- : m_jvm(NULL)
-{
- LOGV("JNI Cache Created");
-}
-
-JniLookup::JniLookup(JavaVM *jvm)
- : m_jvm(jvm)
-{
- LOGV("JNI Cache Created");
-}
-
-JniLookup::~JniLookup()
-{
- LOGV("JNI Cache Destroyed");
-}
-
-
-void JniLookup::setJavaVM(JavaVM *jvm)
-{
- LOGV("Assigned JVM to object");
- m_jvm = jvm;
-}
-
-
-jclass JniLookup::findClass(const std::string &name)
-{
- if(!m_jvm)
- return NULL;
-
- // get the class from the JVM
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- LOGE("Error retrieving JNI Environment");
- return NULL;
- }
- const char *c = name.c_str();
- jclass cls = env->FindClass(c);
- if(env->ExceptionCheck())
- {
- LOGE("Error finding class: %s", name.c_str());
- return NULL;
- }
-
- return cls;
-}
-
-
-jmethodID JniLookup::findMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
-{
- if(!m_jvm)
- return NULL;
-
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- return NULL;
- }
-
- jmethodID mid = env->GetMethodID(cls, methodName.c_str(), methodSig.c_str());
- if(env->ExceptionCheck())
- {
- return NULL;
- }
-
- return mid;
-}
-
-jmethodID JniLookup::findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
-{
- if(!m_jvm)
- return NULL;
-
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- return NULL;
- }
-
- jmethodID mid = env->GetStaticMethodID(cls, methodName.c_str(), methodSig.c_str());
- if(env->ExceptionCheck())
- {
- return NULL;
- }
-
- return mid;
-}
-
-jfieldID JniLookup::findField(jclass cls, const std::string &fieldName, const std::string &typeStr)
-{
- if(!m_jvm)
- return NULL;
-
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- return NULL;
- }
-
- jfieldID fid = env->GetFieldID(cls, fieldName.c_str(), typeStr.c_str());
- if(env->ExceptionCheck())
- {
- return NULL;
- }
-
- return fid;
-}
-
-jfieldID JniLookup::findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr)
-{
- if(!m_jvm)
- return NULL;
-
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- return NULL;
- }
-
- jfieldID fid = env->GetStaticFieldID(cls, fieldName.c_str(), typeStr.c_str());
- if(env->ExceptionCheck())
- {
- return NULL;
- }
-
- return fid;
-} \ No newline at end of file
diff --git a/java/jni/ZT_jnilookup.h b/java/jni/ZT_jnilookup.h
deleted file mode 100644
index f5bd97d7..00000000
--- a/java/jni/ZT_jnilookup.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * 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/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_JNILOOKUP_H_
-#define ZT_JNILOOKUP_H_
-
-#include <jni.h>
-#include <map>
-#include <string>
-
-
-
-class JniLookup {
-public:
- JniLookup();
- JniLookup(JavaVM *jvm);
- ~JniLookup();
-
- void setJavaVM(JavaVM *jvm);
-
- jclass findClass(const std::string &name);
- jmethodID findMethod(jclass cls, const std::string &methodName, const std::string &methodSig);
- jmethodID findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig);
- jfieldID findField(jclass cls, const std::string &fieldName, const std::string &typeStr);
- jfieldID findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr);
-private:
- JavaVM *m_jvm;
-};
-
-#endif \ No newline at end of file
diff --git a/java/jni/ZT_jniutils.cpp b/java/jni/ZT_jniutils.cpp
index c479f87e..17e6a9b3 100644
--- a/java/jni/ZT_jniutils.cpp
+++ b/java/jni/ZT_jniutils.cpp
@@ -17,322 +17,123 @@
*/
#include "ZT_jniutils.h"
-#include "ZT_jnilookup.h"
-#include "ZT_jniarray.h"
+
+#include "ZT_jnicache.h"
#include <string>
-#include <assert.h>
+#include <cassert>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
-#include <sys/socket.h>
-
-extern JniLookup lookup;
-#ifdef __cplusplus
-extern "C" {
-#endif
+#define LOG_TAG "Utils"
jobject createResultObject(JNIEnv *env, ZT_ResultCode code)
{
- jclass resultClass = NULL;
-
- jobject resultObject = NULL;
-
- resultClass = lookup.findClass("com/zerotier/sdk/ResultCode");
- if(resultClass == NULL)
- {
- LOGE("Couldn't find ResultCode class");
- return NULL; // exception thrown
- }
-
- std::string fieldName;
- switch(code)
- {
- case ZT_RESULT_OK:
- case ZT_RESULT_OK_IGNORED:
- LOGV("ZT_RESULT_OK");
- fieldName = "RESULT_OK";
- break;
- case ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY:
- LOGV("ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY");
- fieldName = "RESULT_FATAL_ERROR_OUT_OF_MEMORY";
- break;
- case ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED:
- LOGV("RESULT_FATAL_ERROR_DATA_STORE_FAILED");
- fieldName = "RESULT_FATAL_ERROR_DATA_STORE_FAILED";
- break;
- case ZT_RESULT_ERROR_NETWORK_NOT_FOUND:
- LOGV("ZT_RESULT_ERROR_NETWORK_NOT_FOUND");
- fieldName = "RESULT_ERROR_NETWORK_NOT_FOUND";
- break;
- case ZT_RESULT_ERROR_UNSUPPORTED_OPERATION:
- LOGV("ZT_RESULT_ERROR_UNSUPPORTED_OPERATION");
- fieldName = "RESULT_ERROR_UNSUPPORTED_OPERATION";
- break;
- case ZT_RESULT_ERROR_BAD_PARAMETER:
- LOGV("ZT_RESULT_ERROR_BAD_PARAMETER");
- fieldName = "ZT_RESULT_ERROR_BAD_PARAMETER";
- break;
- case ZT_RESULT_FATAL_ERROR_INTERNAL:
- default:
- LOGV("ZT_RESULT_FATAL_ERROR_INTERNAL");
- fieldName = "RESULT_FATAL_ERROR_INTERNAL";
- break;
- }
-
- jfieldID enumField = lookup.findStaticField(resultClass, fieldName.c_str(), "Lcom/zerotier/sdk/ResultCode;");
- if(env->ExceptionCheck() || enumField == NULL)
- {
- LOGE("Error on FindStaticField");
+ jobject resultObject = env->CallStaticObjectMethod(ResultCode_class, ResultCode_fromInt_method, code);
+ if(env->ExceptionCheck() || resultObject == NULL) {
+ LOGE("Error creating ResultCode object");
return NULL;
}
- resultObject = env->GetStaticObjectField(resultClass, enumField);
- if(env->ExceptionCheck() || resultObject == NULL)
- {
- LOGE("Error on GetStaticObjectField");
- }
return resultObject;
}
jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status)
{
- jobject statusObject = NULL;
-
- jclass statusClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkStatus");
- if(statusClass == NULL)
- {
- return NULL; // exception thrown
- }
-
- std::string fieldName;
- switch(status)
- {
- case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION:
- fieldName = "NETWORK_STATUS_REQUESTING_CONFIGURATION";
- break;
- case ZT_NETWORK_STATUS_OK:
- fieldName = "NETWORK_STATUS_OK";
- break;
- case ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED:
- fieldName = "NETWORK_STATUS_AUTHENTICATION_REQUIRED";
- break;
- case ZT_NETWORK_STATUS_ACCESS_DENIED:
- fieldName = "NETWORK_STATUS_ACCESS_DENIED";
- break;
- case ZT_NETWORK_STATUS_NOT_FOUND:
- fieldName = "NETWORK_STATUS_NOT_FOUND";
- break;
- case ZT_NETWORK_STATUS_PORT_ERROR:
- fieldName = "NETWORK_STATUS_PORT_ERROR";
- break;
- case ZT_NETWORK_STATUS_CLIENT_TOO_OLD:
- fieldName = "NETWORK_STATUS_CLIENT_TOO_OLD";
- break;
+ jobject statusObject = env->CallStaticObjectMethod(VirtualNetworkStatus_class, VirtualNetworkStatus_fromInt_method, status);
+ if (env->ExceptionCheck() || statusObject == NULL) {
+ LOGE("Error creating VirtualNetworkStatus object");
+ return NULL;
}
- jfieldID enumField = lookup.findStaticField(statusClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkStatus;");
-
- statusObject = env->GetStaticObjectField(statusClass, enumField);
-
return statusObject;
}
jobject createEvent(JNIEnv *env, ZT_Event event)
{
- jclass eventClass = NULL;
- jobject eventObject = NULL;
-
- eventClass = lookup.findClass("com/zerotier/sdk/Event");
- if(eventClass == NULL)
- {
+ jobject eventObject = env->CallStaticObjectMethod(Event_class, Event_fromInt_method, event);
+ if (env->ExceptionCheck() || eventObject == NULL) {
+ LOGE("Error creating Event object");
return NULL;
}
- std::string fieldName;
- switch(event)
- {
- case ZT_EVENT_UP:
- fieldName = "EVENT_UP";
- break;
- case ZT_EVENT_OFFLINE:
- fieldName = "EVENT_OFFLINE";
- break;
- case ZT_EVENT_ONLINE:
- fieldName = "EVENT_ONLINE";
- break;
- case ZT_EVENT_DOWN:
- fieldName = "EVENT_DOWN";
- break;
- case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION:
- fieldName = "EVENT_FATAL_ERROR_IDENTITY_COLLISION";
- break;
- case ZT_EVENT_TRACE:
- fieldName = "EVENT_TRACE";
- break;
- case ZT_EVENT_USER_MESSAGE:
- break;
- case ZT_EVENT_REMOTE_TRACE:
- default:
- break;
- }
-
- jfieldID enumField = lookup.findStaticField(eventClass, fieldName.c_str(), "Lcom/zerotier/sdk/Event;");
-
- eventObject = env->GetStaticObjectField(eventClass, enumField);
-
return eventObject;
}
jobject createPeerRole(JNIEnv *env, ZT_PeerRole role)
{
- jclass peerRoleClass = NULL;
- jobject peerRoleObject = NULL;
-
- peerRoleClass = lookup.findClass("com/zerotier/sdk/PeerRole");
- if(peerRoleClass == NULL)
- {
+ jobject peerRoleObject = env->CallStaticObjectMethod(PeerRole_class, PeerRole_fromInt_method, role);
+ if (env->ExceptionCheck() || peerRoleObject == NULL) {
+ LOGE("Error creating PeerRole object");
return NULL;
}
- std::string fieldName;
- switch(role)
- {
- case ZT_PEER_ROLE_LEAF:
- fieldName = "PEER_ROLE_LEAF";
- break;
- case ZT_PEER_ROLE_MOON:
- fieldName = "PEER_ROLE_MOON";
- break;
- case ZT_PEER_ROLE_PLANET:
- fieldName = "PEER_ROLE_PLANET";
- break;
- }
-
- jfieldID enumField = lookup.findStaticField(peerRoleClass, fieldName.c_str(), "Lcom/zerotier/sdk/PeerRole;");
-
- peerRoleObject = env->GetStaticObjectField(peerRoleClass, enumField);
-
return peerRoleObject;
}
jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type)
{
- jclass vntypeClass = NULL;
- jobject vntypeObject = NULL;
-
- vntypeClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkType");
- if(env->ExceptionCheck() || vntypeClass == NULL)
- {
+ jobject vntypeObject = env->CallStaticObjectMethod(VirtualNetworkType_class, VirtualNetworkType_fromInt_method, type);
+ if (env->ExceptionCheck() || vntypeObject == NULL) {
+ LOGE("Error creating VirtualNetworkType object");
return NULL;
}
- std::string fieldName;
- switch(type)
- {
- case ZT_NETWORK_TYPE_PRIVATE:
- fieldName = "NETWORK_TYPE_PRIVATE";
- break;
- case ZT_NETWORK_TYPE_PUBLIC:
- fieldName = "NETWORK_TYPE_PUBLIC";
- break;
- }
-
- jfieldID enumField = lookup.findStaticField(vntypeClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkType;");
- vntypeObject = env->GetStaticObjectField(vntypeClass, enumField);
return vntypeObject;
}
jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT_VirtualNetworkConfigOperation op)
{
- jclass vnetConfigOpClass = NULL;
- jobject vnetConfigOpObject = NULL;
-
- vnetConfigOpClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfigOperation");
- if(env->ExceptionCheck() || vnetConfigOpClass == NULL)
- {
+ jobject vnetConfigOpObject = env->CallStaticObjectMethod(VirtualNetworkConfigOperation_class, VirtualNetworkConfigOperation_fromInt_method, op);
+ if (env->ExceptionCheck() || vnetConfigOpObject == NULL) {
+ LOGE("Error creating VirtualNetworkConfigOperation object");
return NULL;
}
- std::string fieldName;
- switch(op)
- {
- case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP:
- fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_UP";
- break;
- case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE:
- fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE";
- break;
- case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN:
- fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN";
- break;
- case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY:
- fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY";
- break;
- }
-
- jfieldID enumField = lookup.findStaticField(vnetConfigOpClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkConfigOperation;");
- vnetConfigOpObject = env->GetStaticObjectField(vnetConfigOpClass, enumField);
return vnetConfigOpObject;
}
jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr)
{
- LOGV("newInetAddress");
- jclass inetAddressClass = NULL;
- jmethodID inetAddress_getByAddress = NULL;
-
- inetAddressClass = lookup.findClass("java/net/InetAddress");
- if(env->ExceptionCheck() || inetAddressClass == NULL)
- {
- LOGE("Error finding InetAddress class");
- return NULL;
- }
-
- inetAddress_getByAddress = lookup.findStaticMethod(
- inetAddressClass, "getByAddress", "([B)Ljava/net/InetAddress;");
- if(env->ExceptionCheck() || inetAddress_getByAddress == NULL)
- {
- LOGE("Error finding getByAddress() static method");
- return NULL;
- }
-
jobject inetAddressObj = NULL;
switch(addr.ss_family)
{
case AF_INET6:
{
sockaddr_in6 *ipv6 = (sockaddr_in6*)&addr;
- jbyteArray buff = env->NewByteArray(16);
- if(buff == NULL)
+ const unsigned char *bytes = reinterpret_cast<const unsigned char *>(&ipv6->sin6_addr.s6_addr);
+
+ jbyteArray buff = newByteArray(env, bytes, 16);
+ if(env->ExceptionCheck() || buff == NULL)
{
- LOGE("Error creating IPV6 byte array");
return NULL;
}
- env->SetByteArrayRegion(buff, 0, 16, (jbyte*)ipv6->sin6_addr.s6_addr);
inetAddressObj = env->CallStaticObjectMethod(
- inetAddressClass, inetAddress_getByAddress, buff);
+ InetAddress_class, InetAddress_getByAddress_method, buff);
}
break;
case AF_INET:
{
sockaddr_in *ipv4 = (sockaddr_in*)&addr;
- jbyteArray buff = env->NewByteArray(4);
- if(buff == NULL)
+ const unsigned char *bytes = reinterpret_cast<const unsigned char *>(&ipv4->sin_addr.s_addr);
+ jbyteArray buff = newByteArray(env, bytes, 4);
+ if(env->ExceptionCheck() || buff == NULL)
{
- LOGE("Error creating IPV4 byte array");
return NULL;
}
- env->SetByteArrayRegion(buff, 0, 4, (jbyte*)&ipv4->sin_addr);
inetAddressObj = env->CallStaticObjectMethod(
- inetAddressClass, inetAddress_getByAddress, buff);
+ InetAddress_class, InetAddress_getByAddress_method, buff);
}
break;
+ default:
+ {
+ assert(false && "addr.ss_family is neither AF_INET6 nor AF_INET");
+ }
}
if(env->ExceptionCheck() || inetAddressObj == NULL) {
LOGE("Error creating InetAddress object");
@@ -342,693 +143,486 @@ jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr)
return inetAddressObj;
}
-jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr)
-{
- LOGV("newInetSocketAddress Called");
- jclass inetSocketAddressClass = NULL;
- jmethodID inetSocketAddress_constructor = NULL;
-
- inetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress");
- if(env->ExceptionCheck() || inetSocketAddressClass == NULL)
- {
- LOGE("Error finding InetSocketAddress Class");
- return NULL;
- }
-
- jobject inetAddressObject = NULL;
-
- if(addr.ss_family != 0)
- {
- inetAddressObject = newInetAddress(env, addr);
-
- if(env->ExceptionCheck() || inetAddressObject == NULL)
- {
- LOGE("Error creating new inet address");
- return NULL;
- }
- }
- else
- {
- return NULL;
- }
-
- inetSocketAddress_constructor = lookup.findMethod(
- inetSocketAddressClass, "<init>", "(Ljava/net/InetAddress;I)V");
- if(env->ExceptionCheck() || inetSocketAddress_constructor == NULL)
- {
- LOGE("Error finding InetSocketAddress constructor");
- return NULL;
- }
+int addressPort(const sockaddr_storage addr) {
int port = 0;
switch(addr.ss_family)
{
case AF_INET6:
{
- LOGV("IPV6 Address");
sockaddr_in6 *ipv6 = (sockaddr_in6*)&addr;
port = ntohs(ipv6->sin6_port);
- LOGV("Port %d", port);
}
- break;
+ break;
case AF_INET:
{
- LOGV("IPV4 Address");
sockaddr_in *ipv4 = (sockaddr_in*)&addr;
port = ntohs(ipv4->sin_port);
- LOGV("Port: %d", port);
}
- break;
+ break;
default:
{
- break;
+ assert(false && "addr.ss_family is neither AF_INET6 nor AF_INET");
}
}
-
- jobject inetSocketAddressObject = env->NewObject(inetSocketAddressClass, inetSocketAddress_constructor, inetAddressObject, port);
- if(env->ExceptionCheck() || inetSocketAddressObject == NULL) {
- LOGE("Error creating InetSocketAddress object");
- }
- return inetSocketAddressObject;
+ return port;
}
-jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp)
+//
+// addr may be empty
+//
+// may return NULL
+//
+jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr)
{
- LOGV("newPeerPhysicalPath Called");
- jclass pppClass = NULL;
-
- jfieldID addressField = NULL;
- jfieldID lastSendField = NULL;
- jfieldID lastReceiveField = NULL;
- jfieldID preferredField = NULL;
-
- jmethodID ppp_constructor = NULL;
-
- pppClass = lookup.findClass("com/zerotier/sdk/PeerPhysicalPath");
- if(env->ExceptionCheck() || pppClass == NULL)
+ if(isSocketAddressEmpty(addr))
{
- LOGE("Error finding PeerPhysicalPath class");
return NULL;
}
- addressField = lookup.findField(pppClass, "address", "Ljava/net/InetSocketAddress;");
- if(env->ExceptionCheck() || addressField == NULL)
- {
- LOGE("Error finding address field");
- return NULL;
- }
+ jobject inetAddressObject = newInetAddress(env, addr);
- lastSendField = lookup.findField(pppClass, "lastSend", "J");
- if(env->ExceptionCheck() || lastSendField == NULL)
+ if(env->ExceptionCheck() || inetAddressObject == NULL)
{
- LOGE("Error finding lastSend field");
return NULL;
}
- lastReceiveField = lookup.findField(pppClass, "lastReceive", "J");
- if(env->ExceptionCheck() || lastReceiveField == NULL)
- {
- LOGE("Error finding lastReceive field");
- return NULL;
- }
+ int port = addressPort(addr);
- preferredField = lookup.findField(pppClass, "preferred", "Z");
- if(env->ExceptionCheck() || preferredField == NULL)
- {
- LOGE("Error finding preferred field");
+ jobject inetSocketAddressObject = env->NewObject(InetSocketAddress_class, InetSocketAddress_ctor, inetAddressObject, port);
+ if(env->ExceptionCheck() || inetSocketAddressObject == NULL) {
+ LOGE("Error creating InetSocketAddress object");
return NULL;
}
+ return inetSocketAddressObject;
+}
- ppp_constructor = lookup.findMethod(pppClass, "<init>", "()V");
- if(env->ExceptionCheck() || ppp_constructor == NULL)
- {
- LOGE("Error finding PeerPhysicalPath constructor");
+jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp)
+{
+ //
+ // may be NULL
+ //
+ jobject addressObject = newInetSocketAddress(env, ppp.address);
+ if(env->ExceptionCheck()) {
return NULL;
}
- jobject pppObject = env->NewObject(pppClass, ppp_constructor);
+ jobject pppObject = env->NewObject(
+ PeerPhysicalPath_class,
+ PeerPhysicalPath_ctor,
+ addressObject,
+ ppp.lastSend,
+ ppp.lastReceive,
+ ppp.preferred);
if(env->ExceptionCheck() || pppObject == NULL)
{
LOGE("Error creating PPP object");
- return NULL; // out of memory
- }
-
- jobject addressObject = newInetSocketAddress(env, ppp.address);
- if(env->ExceptionCheck() || addressObject == NULL) {
- LOGE("Error creating InetSocketAddress object");
return NULL;
}
- env->SetObjectField(pppObject, addressField, addressObject);
- env->SetLongField(pppObject, lastSendField, ppp.lastSend);
- env->SetLongField(pppObject, lastReceiveField, ppp.lastReceive);
- env->SetBooleanField(pppObject, preferredField, ppp.preferred);
-
- if(env->ExceptionCheck()) {
- LOGE("Exception assigning fields to PeerPhysicalPath object");
- }
-
return pppObject;
}
jobject newPeer(JNIEnv *env, const ZT_Peer &peer)
{
- LOGV("newPeer called");
-
- jclass peerClass = NULL;
-
- jfieldID addressField = NULL;
- jfieldID versionMajorField = NULL;
- jfieldID versionMinorField = NULL;
- jfieldID versionRevField = NULL;
- jfieldID latencyField = NULL;
- jfieldID roleField = NULL;
- jfieldID pathsField = NULL;
-
- jmethodID peer_constructor = NULL;
-
- peerClass = lookup.findClass("com/zerotier/sdk/Peer");
- if(env->ExceptionCheck() || peerClass == NULL)
- {
- LOGE("Error finding Peer class");
- return NULL;
- }
-
- addressField = lookup.findField(peerClass, "address", "J");
- if(env->ExceptionCheck() || addressField == NULL)
- {
- LOGE("Error finding address field of Peer object");
- return NULL;
- }
-
- versionMajorField = lookup.findField(peerClass, "versionMajor", "I");
- if(env->ExceptionCheck() || versionMajorField == NULL)
- {
- LOGE("Error finding versionMajor field of Peer object");
- return NULL;
- }
-
- versionMinorField = lookup.findField(peerClass, "versionMinor", "I");
- if(env->ExceptionCheck() || versionMinorField == NULL)
- {
- LOGE("Error finding versionMinor field of Peer object");
- return NULL;
- }
-
- versionRevField = lookup.findField(peerClass, "versionRev", "I");
- if(env->ExceptionCheck() || versionRevField == NULL)
- {
- LOGE("Error finding versionRev field of Peer object");
- return NULL;
- }
-
- latencyField = lookup.findField(peerClass, "latency", "I");
- if(env->ExceptionCheck() || latencyField == NULL)
- {
- LOGE("Error finding latency field of Peer object");
- return NULL;
- }
-
- roleField = lookup.findField(peerClass, "role", "Lcom/zerotier/sdk/PeerRole;");
- if(env->ExceptionCheck() || roleField == NULL)
+ jobject peerRoleObj = createPeerRole(env, peer.role);
+ if(env->ExceptionCheck() || peerRoleObj == NULL)
{
- LOGE("Error finding role field of Peer object");
- return NULL;
- }
-
- pathsField = lookup.findField(peerClass, "paths", "[Lcom/zerotier/sdk/PeerPhysicalPath;");
- if(env->ExceptionCheck() || pathsField == NULL)
- {
- LOGE("Error finding paths field of Peer object");
- return NULL;
+ return NULL; // out of memory
}
- peer_constructor = lookup.findMethod(peerClass, "<init>", "()V");
- if(env->ExceptionCheck() || peer_constructor == NULL)
- {
- LOGE("Error finding Peer constructor");
+ jobjectArray arrayObject = newPeerPhysicalPathArray(env, peer.paths, peer.pathCount);
+ if (env->ExceptionCheck() || arrayObject == NULL) {
return NULL;
}
- jobject peerObject = env->NewObject(peerClass, peer_constructor);
+ jobject peerObject = env->NewObject(
+ Peer_class,
+ Peer_ctor,
+ peer.address,
+ peer.versionMajor,
+ peer.versionMinor,
+ peer.versionRev,
+ peer.latency,
+ peerRoleObj,
+ arrayObject);
if(env->ExceptionCheck() || peerObject == NULL)
{
LOGE("Error creating Peer object");
- return NULL; // out of memory
- }
-
- env->SetLongField(peerObject, addressField, (jlong)peer.address);
- env->SetIntField(peerObject, versionMajorField, peer.versionMajor);
- env->SetIntField(peerObject, versionMinorField, peer.versionMinor);
- env->SetIntField(peerObject, versionRevField, peer.versionRev);
- env->SetIntField(peerObject, latencyField, peer.latency);
- env->SetObjectField(peerObject, roleField, createPeerRole(env, peer.role));
-
- jclass peerPhysicalPathClass = lookup.findClass("com/zerotier/sdk/PeerPhysicalPath");
- if(env->ExceptionCheck() || peerPhysicalPathClass == NULL)
- {
- LOGE("Error finding PeerPhysicalPath class");
return NULL;
}
- jobjectArray arrayObject = env->NewObjectArray(
- peer.pathCount, peerPhysicalPathClass, NULL);
- if(env->ExceptionCheck() || arrayObject == NULL)
- {
- LOGE("Error creating PeerPhysicalPath[] array");
- return NULL;
- }
-
- for(unsigned int i = 0; i < peer.pathCount; ++i)
- {
- jobject path = newPeerPhysicalPath(env, peer.paths[i]);
-
- env->SetObjectArrayElement(arrayObject, i, path);
- if(env->ExceptionCheck()) {
- LOGE("exception assigning PeerPhysicalPath to array");
- break;
- }
- }
-
- env->SetObjectField(peerObject, pathsField, arrayObject);
-
return peerObject;
}
jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &vnetConfig)
{
- jclass vnetConfigClass = NULL;
- jmethodID vnetConfig_constructor = NULL;
- jfieldID nwidField = NULL;
- jfieldID macField = NULL;
- jfieldID nameField = NULL;
- jfieldID statusField = NULL;
- jfieldID typeField = NULL;
- jfieldID mtuField = NULL;
- jfieldID dhcpField = NULL;
- jfieldID bridgeField = NULL;
- jfieldID broadcastEnabledField = NULL;
- jfieldID portErrorField = NULL;
- jfieldID netconfRevisionField = NULL;
- jfieldID assignedAddressesField = NULL;
- jfieldID routesField = NULL;
- jfieldID dnsField = NULL;
-
- vnetConfigClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfig");
- if(vnetConfigClass == NULL)
- {
- LOGE("Couldn't find com.zerotier.sdk.VirtualNetworkConfig");
- return NULL;
- }
-
- vnetConfig_constructor = lookup.findMethod(
- vnetConfigClass, "<init>", "()V");
- if(env->ExceptionCheck() || vnetConfig_constructor == NULL)
+ jstring nameStr = env->NewStringUTF(vnetConfig.name);
+ if(env->ExceptionCheck() || nameStr == NULL)
{
- LOGE("Couldn't find VirtualNetworkConfig Constructor");
- return NULL;
+ LOGE("Exception creating new string");
+ return NULL; // out of memory
}
- jobject vnetConfigObj = env->NewObject(vnetConfigClass, vnetConfig_constructor);
- if(env->ExceptionCheck() || vnetConfigObj == NULL)
+ jobject statusObject = createVirtualNetworkStatus(env, vnetConfig.status);
+ if(env->ExceptionCheck() || statusObject == NULL)
{
- LOGE("Error creating new VirtualNetworkConfig object");
return NULL;
}
- nwidField = lookup.findField(vnetConfigClass, "nwid", "J");
- if(env->ExceptionCheck() || nwidField == NULL)
+ jobject typeObject = createVirtualNetworkType(env, vnetConfig.type);
+ if(env->ExceptionCheck() || typeObject == NULL)
{
- LOGE("Error getting nwid field");
return NULL;
}
- macField = lookup.findField(vnetConfigClass, "mac", "J");
- if(env->ExceptionCheck() || macField == NULL)
- {
- LOGE("Error getting mac field");
+ jobjectArray assignedAddrArrayObj = newInetSocketAddressArray(env, vnetConfig.assignedAddresses, vnetConfig.assignedAddressCount);
+ if (env->ExceptionCheck() || assignedAddrArrayObj == NULL) {
return NULL;
}
- nameField = lookup.findField(vnetConfigClass, "name", "Ljava/lang/String;");
- if(env->ExceptionCheck() || nameField == NULL)
- {
- LOGE("Error getting name field");
+ jobjectArray routesArrayObj = newVirtualNetworkRouteArray(env, vnetConfig.routes, vnetConfig.routeCount);
+ if (env->ExceptionCheck() || routesArrayObj == NULL) {
return NULL;
}
- statusField = lookup.findField(vnetConfigClass, "status", "Lcom/zerotier/sdk/VirtualNetworkStatus;");
- if(env->ExceptionCheck() || statusField == NULL)
- {
- LOGE("Error getting status field");
+ //
+ // may be NULL
+ //
+ jobject dnsObj = newVirtualNetworkDNS(env, vnetConfig.dns);
+ if(env->ExceptionCheck()) {
return NULL;
}
- typeField = lookup.findField(vnetConfigClass, "type", "Lcom/zerotier/sdk/VirtualNetworkType;");
- if(env->ExceptionCheck() || typeField == NULL)
+ jobject vnetConfigObj = env->NewObject(
+ VirtualNetworkConfig_class,
+ VirtualNetworkConfig_ctor,
+ vnetConfig.nwid,
+ vnetConfig.mac,
+ nameStr,
+ statusObject,
+ typeObject,
+ vnetConfig.mtu,
+ vnetConfig.dhcp,
+ vnetConfig.bridge,
+ vnetConfig.broadcastEnabled,
+ //
+ // ANDROID-56: temporarily remove parameters to prevent crashing
+ //
+// vnetConfig.portError,
+// vnetConfig.netconfRevision,
+ assignedAddrArrayObj,
+ routesArrayObj,
+ dnsObj);
+ if(env->ExceptionCheck() || vnetConfigObj == NULL)
{
- LOGE("Error getting type field");
+ LOGE("Error creating new VirtualNetworkConfig object");
return NULL;
}
- mtuField = lookup.findField(vnetConfigClass, "mtu", "I");
- if(env->ExceptionCheck() || mtuField == NULL)
- {
- LOGE("Error getting mtu field");
- return NULL;
- }
+ return vnetConfigObj;
+}
- dhcpField = lookup.findField(vnetConfigClass, "dhcp", "Z");
- if(env->ExceptionCheck() || dhcpField == NULL)
+jobject newVersion(JNIEnv *env, int major, int minor, int rev)
+{
+ // create a com.zerotier.sdk.Version object
+ jobject versionObj = env->NewObject(Version_class, Version_ctor, major, minor, rev);
+ if(env->ExceptionCheck() || versionObj == NULL)
{
- LOGE("Error getting dhcp field");
+ LOGE("Error creating new Version object");
return NULL;
}
- bridgeField = lookup.findField(vnetConfigClass, "bridge", "Z");
- if(env->ExceptionCheck() || bridgeField == NULL)
- {
- LOGE("Error getting bridge field");
- return NULL;
- }
+ return versionObj;
+}
- broadcastEnabledField = lookup.findField(vnetConfigClass, "broadcastEnabled", "Z");
- if(env->ExceptionCheck() || broadcastEnabledField == NULL)
- {
- LOGE("Error getting broadcastEnabled field");
+jobject newVirtualNetworkRoute(JNIEnv *env, const ZT_VirtualNetworkRoute &route)
+{
+ //
+ // may be NULL
+ //
+ jobject targetObj = newInetSocketAddress(env, route.target);
+ if (env->ExceptionCheck()) {
return NULL;
}
- portErrorField = lookup.findField(vnetConfigClass, "portError", "I");
- if(env->ExceptionCheck() || portErrorField == NULL)
- {
- LOGE("Error getting portError field");
+ //
+ // may be NULL
+ //
+ jobject viaObj = newInetSocketAddress(env, route.via);
+ if (env->ExceptionCheck()) {
return NULL;
}
- netconfRevisionField = lookup.findField(vnetConfigClass, "netconfRevision", "J");
- if(env->ExceptionCheck() || netconfRevisionField == NULL)
+ jobject routeObj = env->NewObject(
+ VirtualNetworkRoute_class,
+ VirtualNetworkRoute_ctor,
+ targetObj,
+ viaObj,
+ route.flags,
+ route.metric);
+ if(env->ExceptionCheck() || routeObj == NULL)
{
- LOGE("Error getting netconfRevision field");
+ LOGE("Exception creating VirtualNetworkRoute");
return NULL;
}
- assignedAddressesField = lookup.findField(vnetConfigClass, "assignedAddresses",
- "[Ljava/net/InetSocketAddress;");
- if(env->ExceptionCheck() || assignedAddressesField == NULL)
- {
- LOGE("Error getting assignedAddresses field");
- return NULL;
- }
+ return routeObj;
+}
- routesField = lookup.findField(vnetConfigClass, "routes",
- "[Lcom/zerotier/sdk/VirtualNetworkRoute;");
- if(env->ExceptionCheck() || routesField == NULL)
- {
- LOGE("Error getting routes field");
+//
+// may return NULL
+//
+jobject newVirtualNetworkDNS(JNIEnv *env, const ZT_VirtualNetworkDNS &dns)
+{
+ if (strlen(dns.domain) == 0) {
+ LOGD("dns.domain is empty; returning NULL");
return NULL;
}
- dnsField = lookup.findField(vnetConfigClass, "dns", "Lcom/zerotier/sdk/VirtualNetworkDNS;");
- if(env->ExceptionCheck() || dnsField == NULL)
- {
- LOGE("Error getting DNS field");
+ jstring domain = env->NewStringUTF(dns.domain);
+ if (env->ExceptionCheck() || domain == NULL) {
+ LOGE("Exception creating new string");
return NULL;
}
- env->SetLongField(vnetConfigObj, nwidField, vnetConfig.nwid);
- env->SetLongField(vnetConfigObj, macField, vnetConfig.mac);
- jstring nameStr = env->NewStringUTF(vnetConfig.name);
- if(env->ExceptionCheck() || nameStr == NULL)
- {
- return NULL; // out of memory
- }
- env->SetObjectField(vnetConfigObj, nameField, nameStr);
-
- jobject statusObject = createVirtualNetworkStatus(env, vnetConfig.status);
- if(env->ExceptionCheck() || statusObject == NULL)
- {
+ jobject addrList = env->NewObject(ArrayList_class, ArrayList_ctor, 0);
+ if (env->ExceptionCheck() || addrList == NULL) {
+ LOGE("Exception creating new ArrayList");
return NULL;
}
- env->SetObjectField(vnetConfigObj, statusField, statusObject);
- jobject typeObject = createVirtualNetworkType(env, vnetConfig.type);
- if(env->ExceptionCheck() || typeObject == NULL)
- {
- return NULL;
- }
- env->SetObjectField(vnetConfigObj, typeField, typeObject);
+ for (int i = 0; i < ZT_MAX_DNS_SERVERS; ++i) { //NOLINT
- env->SetIntField(vnetConfigObj, mtuField, (int)vnetConfig.mtu);
- env->SetBooleanField(vnetConfigObj, dhcpField, vnetConfig.dhcp);
- env->SetBooleanField(vnetConfigObj, bridgeField, vnetConfig.bridge);
- env->SetBooleanField(vnetConfigObj, broadcastEnabledField, vnetConfig.broadcastEnabled);
- env->SetIntField(vnetConfigObj, portErrorField, vnetConfig.portError);
+ struct sockaddr_storage tmp = dns.server_addr[i];
- jclass inetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress");
- if(env->ExceptionCheck() || inetSocketAddressClass == NULL)
- {
- LOGE("Error finding InetSocketAddress class");
- return NULL;
- }
-
- jobjectArray assignedAddrArrayObj = env->NewObjectArray(
- vnetConfig.assignedAddressCount, inetSocketAddressClass, NULL);
- if(env->ExceptionCheck() || assignedAddrArrayObj == NULL)
- {
- LOGE("Error creating InetSocketAddress[] array");
- return NULL;
- }
-
- for(unsigned int i = 0; i < vnetConfig.assignedAddressCount; ++i)
- {
- jobject inetAddrObj = newInetSocketAddress(env, vnetConfig.assignedAddresses[i]);
- env->SetObjectArrayElement(assignedAddrArrayObj, i, inetAddrObj);
- if(env->ExceptionCheck())
- {
- LOGE("Error assigning InetSocketAddress to array");
+ //
+ // may be NULL
+ //
+ jobject addr = newInetSocketAddress(env, tmp);
+ if (env->ExceptionCheck()) {
return NULL;
}
- }
-
- env->SetObjectField(vnetConfigObj, assignedAddressesField, assignedAddrArrayObj);
- jclass virtualNetworkRouteClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkRoute");
- if(env->ExceptionCheck() || virtualNetworkRouteClass == NULL)
- {
- LOGE("Error finding VirtualNetworkRoute class");
- return NULL;
- }
-
- jobjectArray routesArrayObj = env->NewObjectArray(
- vnetConfig.routeCount, virtualNetworkRouteClass, NULL);
- if(env->ExceptionCheck() || routesArrayObj == NULL)
- {
- LOGE("Error creating VirtualNetworkRoute[] array");
- return NULL;
- }
+ if (addr == NULL) {
+ continue;
+ }
- for(unsigned int i = 0; i < vnetConfig.routeCount; ++i)
- {
- jobject routeObj = newVirtualNetworkRoute(env, vnetConfig.routes[i]);
- env->SetObjectArrayElement(routesArrayObj, i, routeObj);
+ env->CallBooleanMethod(addrList, ArrayList_add_method, addr);
if(env->ExceptionCheck())
{
- LOGE("Error assigning VirtualNetworkRoute to array");
+ LOGE("Exception calling add");
return NULL;
}
- }
- env->SetObjectField(vnetConfigObj, routesField, routesArrayObj);
+ env->DeleteLocalRef(addr);
+ }
- jobject dnsObj = newVirtualNetworkDNS(env, vnetConfig.dns);
- if (dnsObj != NULL) {
- env->SetObjectField(vnetConfigObj, dnsField, dnsObj);
+ jobject dnsObj = env->NewObject(
+ VirtualNetworkDNS_class,
+ VirtualNetworkDNS_ctor,
+ domain,
+ addrList);
+ if (env->ExceptionCheck() || dnsObj == NULL) {
+ LOGE("Exception creating new VirtualNetworkDNS");
+ return NULL;
}
- return vnetConfigObj;
+ return dnsObj;
}
-jobject newVersion(JNIEnv *env, int major, int minor, int rev)
-{
- // create a com.zerotier.sdk.Version object
- jclass versionClass = NULL;
- jmethodID versionConstructor = NULL;
+jobject newNodeStatus(JNIEnv *env, const ZT_NodeStatus &status) {
- versionClass = lookup.findClass("com/zerotier/sdk/Version");
- if(env->ExceptionCheck() || versionClass == NULL)
+ jstring pubIdentStr = env->NewStringUTF(status.publicIdentity);
+ if(env->ExceptionCheck() || pubIdentStr == NULL)
{
+ LOGE("Exception creating new string");
return NULL;
}
- versionConstructor = lookup.findMethod(
- versionClass, "<init>", "()V");
- if(env->ExceptionCheck() || versionConstructor == NULL)
+ jstring secIdentStr = env->NewStringUTF(status.secretIdentity);
+ if(env->ExceptionCheck() || secIdentStr == NULL)
{
+ LOGE("Exception creating new string");
return NULL;
}
- jobject versionObj = env->NewObject(versionClass, versionConstructor);
- if(env->ExceptionCheck() || versionObj == NULL)
- {
+ jobject nodeStatusObj = env->NewObject(
+ NodeStatus_class,
+ NodeStatus_ctor,
+ status.address,
+ pubIdentStr,
+ secIdentStr,
+ status.online);
+ if(env->ExceptionCheck() || nodeStatusObj == NULL) {
+ LOGE("Exception creating new NodeStatus");
return NULL;
}
- // copy data to Version object
- jfieldID majorField = NULL;
- jfieldID minorField = NULL;
- jfieldID revisionField = NULL;
+ return nodeStatusObj;
+}
- majorField = lookup.findField(versionClass, "major", "I");
- if(env->ExceptionCheck() || majorField == NULL)
- {
- return NULL;
- }
+jobjectArray newPeerArray(JNIEnv *env, const ZT_Peer *peers, size_t count) {
+ return newArrayObject<ZT_Peer, newPeer>(env, peers, count, Peer_class);
+}
- minorField = lookup.findField(versionClass, "minor", "I");
- if(env->ExceptionCheck() || minorField == NULL)
- {
- return NULL;
- }
+jobjectArray newVirtualNetworkConfigArray(JNIEnv *env, const ZT_VirtualNetworkConfig *networks, size_t count) {
+ return newArrayObject<ZT_VirtualNetworkConfig, newNetworkConfig>(env, networks, count, VirtualNetworkConfig_class);
+}
- revisionField = lookup.findField(versionClass, "revision", "I");
- if(env->ExceptionCheck() || revisionField == NULL)
- {
- return NULL;
- }
+jobjectArray newPeerPhysicalPathArray(JNIEnv *env, const ZT_PeerPhysicalPath *paths, size_t count) {
+ return newArrayObject<ZT_PeerPhysicalPath, newPeerPhysicalPath>(env, paths, count, PeerPhysicalPath_class);
+}
- env->SetIntField(versionObj, majorField, (jint)major);
- env->SetIntField(versionObj, minorField, (jint)minor);
- env->SetIntField(versionObj, revisionField, (jint)rev);
+jobjectArray newInetSocketAddressArray(JNIEnv *env, const sockaddr_storage *addresses, size_t count) {
+ return newArrayObject<sockaddr_storage, newInetSocketAddress>(env, addresses, count, InetSocketAddress_class);
+}
- return versionObj;
+jobjectArray newVirtualNetworkRouteArray(JNIEnv *env, const ZT_VirtualNetworkRoute *routes, size_t count) {
+ return newArrayObject<ZT_VirtualNetworkRoute, newVirtualNetworkRoute>(env, routes, count, VirtualNetworkRoute_class);
}
-jobject newVirtualNetworkRoute(JNIEnv *env, const ZT_VirtualNetworkRoute &route)
-{
- jclass virtualNetworkRouteClass = NULL;
- jmethodID routeConstructor = NULL;
+void newArrayObject_logCount(size_t count) {
+ LOGE("count > JSIZE_MAX: %zu", count);
+}
- virtualNetworkRouteClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkRoute");
- if(env->ExceptionCheck() || virtualNetworkRouteClass == NULL)
- {
- return NULL;
- }
+void newArrayObject_log(const char *msg) {
+ LOGE("%s", msg);
+}
- routeConstructor = lookup.findMethod(virtualNetworkRouteClass, "<init>", "()V");
- if(env->ExceptionCheck() || routeConstructor == NULL)
- {
- return NULL;
- }
+jbyteArray newByteArray(JNIEnv *env, const unsigned char *bytes, size_t count) {
- jobject routeObj = env->NewObject(virtualNetworkRouteClass, routeConstructor);
- if(env->ExceptionCheck() || routeObj == NULL)
- {
+ if (count > JSIZE_MAX) {
+ LOGE("count > JSIZE_MAX: %zu", count);
return NULL;
}
- jfieldID targetField = NULL;
- jfieldID viaField = NULL;
- jfieldID flagsField = NULL;
- jfieldID metricField = NULL;
+ jsize jCount = static_cast<jsize>(count);
+ const jbyte *jBytes = reinterpret_cast<const jbyte *>(bytes);
- targetField = lookup.findField(virtualNetworkRouteClass, "target",
- "Ljava/net/InetSocketAddress;");
- if(env->ExceptionCheck() || targetField == NULL)
+ jbyteArray byteArrayObj = env->NewByteArray(jCount);
+ if(byteArrayObj == NULL)
{
+ LOGE("NewByteArray returned NULL");
return NULL;
}
- viaField = lookup.findField(virtualNetworkRouteClass, "via",
- "Ljava/net/InetSocketAddress;");
- if(env->ExceptionCheck() || targetField == NULL)
- {
+ env->SetByteArrayRegion(byteArrayObj, 0, jCount, jBytes);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception when calling SetByteArrayRegion");
return NULL;
}
- flagsField = lookup.findField(virtualNetworkRouteClass, "flags", "I");
- if(env->ExceptionCheck() || flagsField == NULL)
- {
+ return byteArrayObj;
+}
+
+jbyteArray newByteArray(JNIEnv *env, size_t count) {
+
+ if (count > JSIZE_MAX) {
+ LOGE("count > JSIZE_MAX: %zu", count);
return NULL;
}
- metricField = lookup.findField(virtualNetworkRouteClass, "metric", "I");
- if(env->ExceptionCheck() || metricField == NULL)
+ jsize jCount = static_cast<jsize>(count);
+
+ jbyteArray byteArrayObj = env->NewByteArray(jCount);
+ if(byteArrayObj == NULL)
{
+ LOGE("NewByteArray returned NULL");
return NULL;
}
- jobject targetObj = newInetSocketAddress(env, route.target);
- jobject viaObj = newInetSocketAddress(env, route.via);
-
- env->SetObjectField(routeObj, targetField, targetObj);
- env->SetObjectField(routeObj, viaField, viaObj);
- env->SetIntField(routeObj, flagsField, (jint)route.flags);
- env->SetIntField(routeObj, metricField, (jint)route.metric);
+ return byteArrayObj;
+}
- return routeObj;
+bool isSocketAddressEmpty(const sockaddr_storage addr) {
+
+ //
+ // was:
+ // struct sockaddr_storage nullAddress = {0};
+ //
+ // but was getting this warning:
+ // warning: suggest braces around initialization of subobject
+ //
+ // when building ZeroTierOne
+ //
+ sockaddr_storage emptyAddress; //NOLINT
+
+ //
+ // It is possible to assume knowledge about internals of sockaddr_storage and construct
+ // correct 0-initializer, but it is simpler to just treat sockaddr_storage as opaque and
+ // use memset here to fill with 0
+ //
+ // This is also done in InetAddress.hpp for InetAddress
+ //
+ memset(&emptyAddress, 0, sizeof(sockaddr_storage));
+
+ return (memcmp(&addr, &emptyAddress, sizeof(sockaddr_storage)) == 0); //NOLINT
}
-jobject newVirtualNetworkDNS(JNIEnv *env, const ZT_VirtualNetworkDNS &dns)
-{
- jclass virtualNetworkDNSClass = NULL;
- jmethodID dnsConstructor = NULL;
+//
+// returns empty sockaddr_storage on error
+//
+sockaddr_storage fromSocketAddressObject(JNIEnv *env, jobject sockAddressObject) {
- virtualNetworkDNSClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkDNS");
- if (env->ExceptionCheck() || virtualNetworkDNSClass == NULL) {
- return NULL;
- }
+ sockaddr_storage emptyAddress; //NOLINT
- dnsConstructor = lookup.findMethod(virtualNetworkDNSClass, "<init>", "()V");
- if(env->ExceptionCheck() || dnsConstructor == NULL) {
- return NULL;
- }
+ memset(&emptyAddress, 0, sizeof(sockaddr_storage));
- jobject dnsObj = env->NewObject(virtualNetworkDNSClass, dnsConstructor);
- if(env->ExceptionCheck() || dnsObj == NULL) {
- return NULL;
+ jint port = env->CallIntMethod(sockAddressObject, InetSocketAddress_getPort_method);
+ if(env->ExceptionCheck())
+ {
+ LOGE("Exception calling getPort");
+ return emptyAddress;
}
- jfieldID domainField = NULL;
- jfieldID serversField = NULL;
-
- domainField = lookup.findField(virtualNetworkDNSClass, "domain", "Ljava/lang/String;");
- if(env->ExceptionCheck() || domainField == NULL)
+ jobject addressObject = env->CallObjectMethod(sockAddressObject, InetSocketAddress_getAddress_method);
+ if(env->ExceptionCheck() || addressObject == NULL)
{
- return NULL;
+ LOGE("Exception calling getAddress");
+ return emptyAddress;
}
- serversField = lookup.findField(virtualNetworkDNSClass, "servers", "Ljava/util/ArrayList;");
- if(env->ExceptionCheck() || serversField == NULL) {
- return NULL;
+ jbyteArray addressArrayObj = reinterpret_cast<jbyteArray>(env->CallObjectMethod(addressObject, InetAddress_getAddress_method));
+ if(env->ExceptionCheck() || addressArrayObj == NULL)
+ {
+ LOGE("Exception calling getAddress");
+ return emptyAddress;
}
- if (strlen(dns.domain) > 0) {
- InitListJNI(env);
- jstring domain = env->NewStringUTF(dns.domain);
+ sockaddr_storage addr = {};
- jobject addrArray = env->NewObject(java_util_ArrayList, java_util_ArrayList_, 0);
+ if (env->IsInstanceOf(addressObject, Inet4Address_class)) {
- struct sockaddr_storage nullAddr;
- memset(&nullAddr, 0, sizeof(struct sockaddr_storage));
- for(int i = 0; i < ZT_MAX_DNS_SERVERS; ++i) {
- struct sockaddr_storage tmp = dns.server_addr[i];
+ // IPV4
- if (memcmp(&tmp, &nullAddr, sizeof(struct sockaddr_storage)) != 0) {
- jobject addr = newInetSocketAddress(env, tmp);
- env->CallBooleanMethod(addrArray, java_util_ArrayList_add, addr);
- env->DeleteLocalRef(addr);
- }
- }
+ assert(env->GetArrayLength(addressArrayObj) == 4);
+
+ sockaddr_in *addr_4 = reinterpret_cast<sockaddr_in *>(&addr);
+ addr_4->sin_family = AF_INET;
+ addr_4->sin_port = htons(port);
+
+ void *data = env->GetPrimitiveArrayCritical(addressArrayObj, NULL);
+ memcpy(&addr_4->sin_addr.s_addr, data, 4);
+ env->ReleasePrimitiveArrayCritical(addressArrayObj, data, 0);
- env->SetObjectField(dnsObj, domainField, domain);
- env->SetObjectField(dnsObj, serversField, addrArray);
+ } else if (env->IsInstanceOf(addressObject, Inet6Address_class)) {
- return dnsObj;
+ // IPV6
+
+ assert(env->GetArrayLength(addressArrayObj) == 16);
+
+ sockaddr_in6 *addr_6 = reinterpret_cast<sockaddr_in6 *>(&addr);
+ addr_6->sin6_family = AF_INET6;
+ addr_6->sin6_port = htons(port);
+
+ void *data = env->GetPrimitiveArrayCritical(addressArrayObj, NULL);
+ memcpy(&addr_6->sin6_addr.s6_addr, data, 16);
+ env->ReleasePrimitiveArrayCritical(addressArrayObj, data, 0);
+
+ } else {
+ assert(false && "addressObject is neither Inet4Address nor Inet6Address");
}
- return NULL;
-}
-#ifdef __cplusplus
+ return addr;
}
-#endif
diff --git a/java/jni/ZT_jniutils.h b/java/jni/ZT_jniutils.h
index 3e81b934..23664a73 100644
--- a/java/jni/ZT_jniutils.h
+++ b/java/jni/ZT_jniutils.h
@@ -15,18 +15,15 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#ifndef ZT_jniutils_h_
#define ZT_jniutils_h_
-#include <stdio.h>
+
#include <jni.h>
#include <ZeroTierOne.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define LOG_TAG "ZeroTierOneJNI"
+#include <limits> // for numeric_limits
+#include <sys/socket.h> // for sockaddr_storage
#if defined(__ANDROID__)
@@ -55,6 +52,34 @@ extern "C" {
#define LOGE(...) fprintf(stdout, __VA_ARGS__)
#endif
+//
+// Call GetEnv and assert if there is an error
+//
+#define GETENV(env, vm) \
+ do { \
+ jint getEnvRet; \
+ assert(vm); \
+ if ((getEnvRet = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) != JNI_OK) { \
+ LOGE("Error calling GetEnv: %d", getEnvRet); \
+ assert(false && "Error calling GetEnv"); \
+ } \
+ } while (false)
+
+//
+// Call GetJavaVM and assert if there is an error
+//
+#define GETJAVAVM(env, vm) \
+ do { \
+ jint getJavaVMRet; \
+ if ((getJavaVMRet = env->GetJavaVM(&vm)) != 0) { \
+ LOGE("Error calling GetJavaVM: %d", getJavaVMRet); \
+ assert(false && "Error calling GetJavaVM"); \
+ } \
+ } while (false)
+
+
+const jsize JSIZE_MAX = std::numeric_limits<jsize>::max();
+
jobject createResultObject(JNIEnv *env, ZT_ResultCode code);
jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status);
jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type);
@@ -64,8 +89,7 @@ jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT_VirtualNetworkConfig
jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr);
jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr);
-
-jobject newMulticastGroup(JNIEnv *env, const ZT_MulticastGroup &mc);
+int addressPort(const sockaddr_storage addr);
jobject newPeer(JNIEnv *env, const ZT_Peer &peer);
jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp);
@@ -78,8 +102,68 @@ jobject newVirtualNetworkRoute(JNIEnv *env, const ZT_VirtualNetworkRoute &route)
jobject newVirtualNetworkDNS(JNIEnv *env, const ZT_VirtualNetworkDNS &dns);
-#ifdef __cplusplus
+jobject newNodeStatus(JNIEnv *env, const ZT_NodeStatus &status);
+
+jobjectArray newPeerArray(JNIEnv *env, const ZT_Peer *peers, size_t count);
+
+jobjectArray newVirtualNetworkConfigArray(JNIEnv *env, const ZT_VirtualNetworkConfig *networks, size_t count);
+
+jobjectArray newPeerPhysicalPathArray(JNIEnv *env, const ZT_PeerPhysicalPath *paths, size_t count);
+
+jobjectArray newInetSocketAddressArray(JNIEnv *env, const sockaddr_storage *addresses, size_t count);
+
+jobjectArray newVirtualNetworkRouteArray(JNIEnv *env, const ZT_VirtualNetworkRoute *routes, size_t count);
+
+//
+// log functions only for newArrayObject below
+//
+void newArrayObject_logCount(size_t count);
+void newArrayObject_log(const char *msg);
+
+//
+// function template for creating array objects
+//
+template <typename T, jobject (*F)(JNIEnv *, const T &)>
+jobjectArray newArrayObject(JNIEnv *env, const T *buffer, size_t count, jclass clazz) {
+
+ if (count > JSIZE_MAX) {
+ newArrayObject_logCount(count);
+ return NULL;
+ }
+
+ jsize jCount = static_cast<jsize>(count);
+
+ jobjectArray arrayObj = env->NewObjectArray(jCount, clazz, NULL);
+ if (env->ExceptionCheck() || arrayObj == NULL) {
+ newArrayObject_log("Error creating array object");
+ return NULL;
+ }
+
+ for (jsize i = 0; i < jCount; i++) {
+
+ jobject obj = F(env, buffer[i]);
+ if(env->ExceptionCheck() || obj == NULL) {
+ return NULL;
+ }
+
+ env->SetObjectArrayElement(arrayObj, i, obj);
+ if(env->ExceptionCheck()) {
+ newArrayObject_log("Error assigning object to array");
+ return NULL;
+ }
+
+ env->DeleteLocalRef(obj);
+ }
+
+ return arrayObj;
}
-#endif
-#endif \ No newline at end of file
+jbyteArray newByteArray(JNIEnv *env, const unsigned char *bytes, size_t count);
+
+jbyteArray newByteArray(JNIEnv *env, size_t count);
+
+bool isSocketAddressEmpty(const sockaddr_storage addr);
+
+sockaddr_storage fromSocketAddressObject(JNIEnv *env, jobject sockAddressObject);
+
+#endif // ZT_jniutils_h_
diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp
index 75af18bc..536c7cb6 100644
--- a/java/jni/com_zerotierone_sdk_Node.cpp
+++ b/java/jni/com_zerotierone_sdk_Node.cpp
@@ -26,47 +26,62 @@
*/
#include "com_zerotierone_sdk_Node.h"
+
+#include "ZT_jnicache.h"
#include "ZT_jniutils.h"
-#include "ZT_jnilookup.h"
#include <ZeroTierOne.h>
#include "Mutex.hpp"
#include <map>
#include <string>
-#include <assert.h>
-#include <string.h>
+#include <cassert>
+#include <cstring>
+#include <cinttypes> // for PRId64
-// global static JNI Lookup Object
-JniLookup lookup;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#define LOG_TAG "Node"
namespace {
struct JniRef
{
- JniRef()
- : jvm(NULL)
- , node(NULL)
- , dataStoreGetListener(NULL)
- , dataStorePutListener(NULL)
- , packetSender(NULL)
- , eventListener(NULL)
- , frameListener(NULL)
- , configListener(NULL)
- , pathChecker(NULL)
- , callbacks(NULL)
- {
- callbacks = (ZT_Node_Callbacks*)malloc(sizeof(ZT_Node_Callbacks));
- memset(callbacks, 0, sizeof(ZT_Node_Callbacks));
- }
+ JniRef(
+ int64_t id,
+ JavaVM *jvm,
+ jobject dataStoreGetListenerLocalIn,
+ jobject dataStorePutListenerLocalIn,
+ jobject packetSenderLocalIn,
+ jobject eventListenerLocalIn,
+ jobject frameListenerLocalIn,
+ jobject configListenerLocalIn,
+ jobject pathCheckerLocalIn)
+ : id(id)
+ , jvm(jvm)
+ , node()
+ , dataStoreGetListener()
+ , dataStorePutListener()
+ , packetSender()
+ , eventListener()
+ , frameListener()
+ , configListener()
+ , pathChecker()
+ , inited() {
+
+ JNIEnv *env;
+ GETENV(env, jvm);
+
+ dataStoreGetListener = env->NewGlobalRef(dataStoreGetListenerLocalIn);
+ dataStorePutListener = env->NewGlobalRef(dataStorePutListenerLocalIn);
+ packetSender = env->NewGlobalRef(packetSenderLocalIn);
+ eventListener = env->NewGlobalRef(eventListenerLocalIn);
+ frameListener = env->NewGlobalRef(frameListenerLocalIn);
+ configListener = env->NewGlobalRef(configListenerLocalIn);
+ pathChecker = env->NewGlobalRef(pathCheckerLocalIn);
+ };
~JniRef()
{
- JNIEnv *env = NULL;
- jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
+ JNIEnv *env;
+ GETENV(env, jvm);
env->DeleteGlobalRef(dataStoreGetListener);
env->DeleteGlobalRef(dataStorePutListener);
@@ -75,9 +90,6 @@ namespace {
env->DeleteGlobalRef(frameListener);
env->DeleteGlobalRef(configListener);
env->DeleteGlobalRef(pathChecker);
-
- free(callbacks);
- callbacks = NULL;
}
int64_t id;
@@ -94,70 +106,76 @@ namespace {
jobject configListener;
jobject pathChecker;
- ZT_Node_Callbacks *callbacks;
+ bool inited;
+
+ bool finishInitializing();
};
+ /*
+ * This must return 0 on success. It can return any OS-dependent error code
+ * on failure, and this results in the network being placed into the
+ * PORT_ERROR state.
+ */
int VirtualNetworkConfigFunctionCallback(
ZT_Node *node,
void *userData,
void *threadData,
uint64_t nwid,
- void **,
+ void **nuptr,
enum ZT_VirtualNetworkConfigOperation operation,
const ZT_VirtualNetworkConfig *config)
{
LOGV("VirtualNetworkConfigFunctionCallback");
JniRef *ref = (JniRef*)userData;
- JNIEnv *env = NULL;
- ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
+ assert(ref);
+ JNIEnv *env;
+ GETENV(env, ref->jvm);
- if (ref->configListener == NULL) {
- LOGE("configListener is NULL");
- return -1;
+ if (env->ExceptionCheck()) {
+ LOGE("Unhandled pending exception");
+ return -100;
}
- jclass configListenerClass = env->GetObjectClass(ref->configListener);
- if(configListenerClass == NULL)
- {
- LOGE("Couldn't find class for VirtualNetworkConfigListener instance");
- return -1;
+ if (ref->configListener == NULL) {
+ LOGE("configListener is NULL");
+ return -101;
}
- jmethodID configListenerCallbackMethod = lookup.findMethod(configListenerClass,
- "onNetworkConfigurationUpdated",
- "(JLcom/zerotier/sdk/VirtualNetworkConfigOperation;Lcom/zerotier/sdk/VirtualNetworkConfig;)I");
- if(configListenerCallbackMethod == NULL)
+ jobject operationObject = createVirtualNetworkConfigOperation(env, operation);
+ if(env->ExceptionCheck() || operationObject == NULL)
{
- LOGE("Couldn't find onVirtualNetworkFrame() method");
- return -2;
+ return -102;
}
- jobject operationObject = createVirtualNetworkConfigOperation(env, operation);
- if(operationObject == NULL)
- {
- LOGE("Error creating VirtualNetworkConfigOperation object");
- return -3;
+ if (config == NULL) {
+ LOGE("Config is NULL");
+ return -103;
}
jobject networkConfigObject = newNetworkConfig(env, *config);
- if(networkConfigObject == NULL)
+ if(env->ExceptionCheck() || networkConfigObject == NULL)
{
- LOGE("Error creating VirtualNetworkConfig object");
- return -4;
+ return -104;
}
- return env->CallIntMethod(
+ jint ret = env->CallIntMethod(
ref->configListener,
- configListenerCallbackMethod,
+ VirtualNetworkConfigListener_onNetworkConfigurationUpdated_method,
(jlong)nwid, operationObject, networkConfigObject);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onNetworkConfigurationUpdated");
+ return -105;
+ }
+
+ return ret;
}
void VirtualNetworkFrameFunctionCallback(ZT_Node *node,
void *userData,
void *threadData,
uint64_t nwid,
- void**,
+ void** nuptr,
uint64_t sourceMac,
uint64_t destMac,
unsigned int etherType,
@@ -167,53 +185,39 @@ namespace {
{
LOGV("VirtualNetworkFrameFunctionCallback");
#ifndef NDEBUG
- unsigned char* local = (unsigned char*)frameData;
- LOGV("Type Bytes: 0x%02x%02x", local[12], local[13]);
+ if (frameLength >= 14) {
+ unsigned char* local = (unsigned char*)frameData;
+ LOGV("Type Bytes: 0x%02x%02x", local[12], local[13]);
+ }
#endif
JniRef *ref = (JniRef*)userData;
+ assert(ref);
assert(ref->node == node);
- JNIEnv *env = NULL;
- ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
+ JNIEnv *env;
+ GETENV(env, ref->jvm);
- if (ref->frameListener == NULL) {
- LOGE("frameListener is NULL");
- return;
- }
-
- jclass frameListenerClass = env->GetObjectClass(ref->frameListener);
- if(env->ExceptionCheck() || frameListenerClass == NULL)
- {
- LOGE("Couldn't find class for VirtualNetworkFrameListener instance");
+ if (env->ExceptionCheck()) {
+ LOGE("Unhandled pending exception");
return;
}
- jmethodID frameListenerCallbackMethod = lookup.findMethod(
- frameListenerClass,
- "onVirtualNetworkFrame", "(JJJJJ[B)V");
- if(env->ExceptionCheck() || frameListenerCallbackMethod == NULL)
- {
- LOGE("Couldn't find onVirtualNetworkFrame() method");
+ if (ref->frameListener == NULL) {
+ LOGE("frameListener is NULL");
return;
}
- jbyteArray dataArray = env->NewByteArray(frameLength);
+ const unsigned char *bytes = static_cast<const unsigned char*>(frameData);
+ jbyteArray dataArray = newByteArray(env, bytes, frameLength);
if(env->ExceptionCheck() || dataArray == NULL)
{
- LOGE("Couldn't create frame data array");
return;
}
- void *data = env->GetPrimitiveArrayCritical(dataArray, NULL);
- memcpy(data, frameData, frameLength);
- env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
-
- if(env->ExceptionCheck())
- {
- LOGE("Error setting frame data to array");
+ env->CallVoidMethod(ref->frameListener, VirtualNetworkFrameListener_onVirtualNetworkFrame_method, (jlong)nwid, (jlong)sourceMac, (jlong)destMac, (jlong)etherType, (jlong)vlanid, dataArray);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onVirtualNetworkFrame");
return;
}
-
- env->CallVoidMethod(ref->frameListener, frameListenerCallbackMethod, (jlong)nwid, (jlong)sourceMac, (jlong)destMac, (jlong)etherType, (jlong)vlanid, dataArray);
}
@@ -224,83 +228,98 @@ namespace {
const void *data) {
LOGV("EventCallback");
JniRef *ref = (JniRef *) userData;
+ assert(ref);
if (ref->node != node && event != ZT_EVENT_UP) {
LOGE("Nodes not equal. ref->node %p, node %p. Event: %d", ref->node, node, event);
return;
}
- JNIEnv *env = NULL;
- ref->jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
-
- if (ref->eventListener == NULL) {
- LOGE("eventListener is NULL");
- return;
- }
-
- jclass eventListenerClass = env->GetObjectClass(ref->eventListener);
- if (eventListenerClass == NULL) {
- LOGE("Couldn't class for EventListener instance");
- return;
- }
+ JNIEnv *env;
+ GETENV(env, ref->jvm);
- jmethodID onEventMethod = lookup.findMethod(eventListenerClass,
- "onEvent", "(Lcom/zerotier/sdk/Event;)V");
- if (onEventMethod == NULL) {
- LOGE("Couldn't find onEvent method");
+ if (env->ExceptionCheck()) {
+ LOGE("Unhandled pending exception");
return;
}
- jmethodID onTraceMethod = lookup.findMethod(eventListenerClass,
- "onTrace", "(Ljava/lang/String;)V");
- if (onTraceMethod == NULL) {
- LOGE("Couldn't find onTrace method");
+ if (ref->eventListener == NULL) {
+ LOGE("eventListener is NULL");
return;
}
jobject eventObject = createEvent(env, event);
- if (eventObject == NULL) {
+ if (env->ExceptionCheck() || eventObject == NULL) {
return;
}
switch (event) {
case ZT_EVENT_UP: {
LOGD("Event Up");
- env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
+ env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onEvent");
+ return;
+ }
break;
}
case ZT_EVENT_OFFLINE: {
LOGD("Event Offline");
- env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
+ env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onEvent");
+ return;
+ }
break;
}
case ZT_EVENT_ONLINE: {
LOGD("Event Online");
- env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
+ env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onEvent");
+ return;
+ }
break;
}
case ZT_EVENT_DOWN: {
LOGD("Event Down");
- env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
+ env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onEvent");
+ return;
+ }
break;
}
case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: {
LOGV("Identity Collision");
// call onEvent()
- env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
+ env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onEvent");
+ return;
+ }
}
break;
case ZT_EVENT_TRACE: {
LOGV("Trace Event");
// call onTrace()
- if (data != NULL) {
- const char *message = (const char *) data;
- jstring messageStr = env->NewStringUTF(message);
- env->CallVoidMethod(ref->eventListener, onTraceMethod, messageStr);
+ if (data == NULL) {
+ break;
+ }
+ const char *message = (const char *) data;
+ jstring messageStr = env->NewStringUTF(message);
+ if (env->ExceptionCheck() || messageStr == NULL) {
+ LOGE("Exception creating new string");
+ return;
+ }
+
+ env->CallVoidMethod(ref->eventListener, EventListener_onTrace_method, messageStr);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onTrace");
+ return;
}
}
break;
case ZT_EVENT_USER_MESSAGE:
case ZT_EVENT_REMOTE_TRACE:
- default:
break;
}
}
@@ -313,93 +332,101 @@ namespace {
const uint64_t id[2],
const void *buffer,
int bufferLength) {
+ LOGV("StatePutFunction");
+
char p[4096] = {0};
bool secure = false;
+ int res = 0;
switch (type) {
case ZT_STATE_OBJECT_IDENTITY_PUBLIC:
- snprintf(p, sizeof(p), "identity.public");
+ res = snprintf(p, sizeof(p), "identity.public");
break;
case ZT_STATE_OBJECT_IDENTITY_SECRET:
- snprintf(p, sizeof(p), "identity.secret");
+ res = snprintf(p, sizeof(p), "identity.secret");
secure = true;
break;
case ZT_STATE_OBJECT_PLANET:
- snprintf(p, sizeof(p), "planet");
+ res = snprintf(p, sizeof(p), "planet");
break;
case ZT_STATE_OBJECT_MOON:
- snprintf(p, sizeof(p), "moons.d/%.16llx.moon", (unsigned long long)id[0]);
+ res = snprintf(p, sizeof(p), "moons.d/%.16" PRIx64 ".moon", id[0]);
break;
case ZT_STATE_OBJECT_NETWORK_CONFIG:
- snprintf(p, sizeof(p), "networks.d/%.16llx.conf", (unsigned long long)id[0]);
+ res = snprintf(p, sizeof(p), "networks.d/%.16" PRIx64 ".conf", id[0]);
break;
case ZT_STATE_OBJECT_PEER:
- snprintf(p, sizeof(p), "peers.d/%.10llx", (unsigned long long)id[0]);
+ res = snprintf(p, sizeof(p), "peers.d/%.10" PRIx64, id[0]);
break;
- default:
+ case ZT_STATE_OBJECT_NULL:
return;
}
- if (strlen(p) < 1) {
+ if (!(0 <= res && res < sizeof(p))) {
+ LOGE("snprintf error: %d", res);
return;
}
JniRef *ref = (JniRef*)userData;
- JNIEnv *env = NULL;
- ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
-
- if (ref->dataStorePutListener == NULL) {
- LOGE("dataStorePutListener is NULL");
- return;
- }
+ assert(ref);
+ JNIEnv *env;
+ GETENV(env, ref->jvm);
- jclass dataStorePutClass = env->GetObjectClass(ref->dataStorePutListener);
- if (dataStorePutClass == NULL)
- {
- LOGE("Couldn't find class for DataStorePutListener instance");
+ if (env->ExceptionCheck()) {
+ LOGE("Unhandled pending exception");
return;
}
- jmethodID dataStorePutCallbackMethod = lookup.findMethod(
- dataStorePutClass,
- "onDataStorePut",
- "(Ljava/lang/String;[BZ)I");
- if(dataStorePutCallbackMethod == NULL)
- {
- LOGE("Couldn't find onDataStorePut method");
+ if (ref->dataStorePutListener == NULL) {
+ LOGE("dataStorePutListener is NULL");
return;
}
- jmethodID deleteMethod = lookup.findMethod(dataStorePutClass,
- "onDelete", "(Ljava/lang/String;)I");
- if(deleteMethod == NULL)
- {
- LOGE("Couldn't find onDelete method");
+ jstring nameStr = env->NewStringUTF(p);
+ if (env->ExceptionCheck() || nameStr == NULL) {
+ LOGE("Exception creating new string");
return;
}
- jstring nameStr = env->NewStringUTF(p);
-
if (bufferLength >= 0) {
LOGD("JNI: Write file: %s", p);
- // set operation
- jbyteArray bufferObj = env->NewByteArray(bufferLength);
+ const unsigned char *bytes = static_cast<const unsigned char *>(buffer);
+ jbyteArray bufferObj = newByteArray(env, bytes, bufferLength);
if(env->ExceptionCheck() || bufferObj == NULL)
{
- LOGE("Error creating byte array buffer!");
return;
}
- env->SetByteArrayRegion(bufferObj, 0, bufferLength, (jbyte*)buffer);
-
- env->CallIntMethod(ref->dataStorePutListener,
- dataStorePutCallbackMethod,
+ int retval = env->CallIntMethod(ref->dataStorePutListener,
+ DataStorePutListener_onDataStorePut_method,
nameStr, bufferObj, secure);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onDataStorePut");
+ return;
+ }
+
+ if (retval != 0) {
+ LOGE("onDataStorePut error: %d", retval);
+ }
+
} else {
LOGD("JNI: Delete file: %s", p);
- env->CallIntMethod(ref->dataStorePutListener, deleteMethod, nameStr);
+ int retval = env->CallIntMethod(ref->dataStorePutListener, DataStorePutListener_onDelete_method, nameStr);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onDelete");
+ return;
+ }
+
+ if (retval != 0) {
+ LOGE("onDelete error: %d", retval);
+ }
}
}
+ /**
+ * This function should return the number of bytes actually stored to the
+ * buffer or -1 if the state object was not found or the buffer was too
+ * small to store it.
+ */
int StateGetFunction(
ZT_Node *node,
void *userData,
@@ -408,86 +435,87 @@ namespace {
const uint64_t id[2],
void *buffer,
unsigned int bufferLength) {
+ LOGV("StateGetFunction");
+
char p[4096] = {0};
+ int res = 0;
switch (type) {
case ZT_STATE_OBJECT_IDENTITY_PUBLIC:
- snprintf(p, sizeof(p), "identity.public");
+ res = snprintf(p, sizeof(p), "identity.public");
break;
case ZT_STATE_OBJECT_IDENTITY_SECRET:
- snprintf(p, sizeof(p), "identity.secret");
+ res = snprintf(p, sizeof(p), "identity.secret");
break;
case ZT_STATE_OBJECT_PLANET:
- snprintf(p, sizeof(p), "planet");
+ res = snprintf(p, sizeof(p), "planet");
break;
case ZT_STATE_OBJECT_MOON:
- snprintf(p, sizeof(p), "moons.d/%.16llx.moon", (unsigned long long)id[0]);
+ res = snprintf(p, sizeof(p), "moons.d/%.16" PRIx64 ".moon", id[0]);
break;
case ZT_STATE_OBJECT_NETWORK_CONFIG:
- snprintf(p, sizeof(p), "networks.d/%.16llx.conf", (unsigned long long)id[0]);
+ res = snprintf(p, sizeof(p), "networks.d/%.16" PRIx64 ".conf", id[0]);
break;
case ZT_STATE_OBJECT_PEER:
- snprintf(p, sizeof(p), "peers.d/%.10llx", (unsigned long long)id[0]);
+ res = snprintf(p, sizeof(p), "peers.d/%.10" PRIx64, id[0]);
break;
- default:
- return -1;
+ case ZT_STATE_OBJECT_NULL:
+ return -100;
}
- if (strlen(p) < 1) {
- return -1;
+ if (!(0 <= res && res < sizeof(p))) {
+ LOGE("snprintf error: %d", res);
+ return -101;
}
JniRef *ref = (JniRef*)userData;
- JNIEnv *env = NULL;
- ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
-
- if (ref->dataStoreGetListener == NULL) {
- LOGE("dataStoreGetListener is NULL");
- return -2;
- }
+ assert(ref);
+ JNIEnv *env;
+ GETENV(env, ref->jvm);
- jclass dataStoreGetClass = env->GetObjectClass(ref->dataStoreGetListener);
- if(dataStoreGetClass == NULL)
- {
- LOGE("Couldn't find class for DataStoreGetListener instance");
- return -2;
+ if (env->ExceptionCheck()) {
+ LOGE("Unhandled pending exception");
+ return -102;
}
- jmethodID dataStoreGetCallbackMethod = lookup.findMethod(
- dataStoreGetClass,
- "onDataStoreGet",
- "(Ljava/lang/String;[B)J");
- if(dataStoreGetCallbackMethod == NULL)
- {
- LOGE("Couldn't find onDataStoreGet method");
- return -2;
+ if (ref->dataStoreGetListener == NULL) {
+ LOGE("dataStoreGetListener is NULL");
+ return -103;
}
jstring nameStr = env->NewStringUTF(p);
- if(nameStr == NULL)
+ if(env->ExceptionCheck() || nameStr == NULL)
{
LOGE("Error creating name string object");
- return -2; // out of memory
+ return -104; // out of memory
}
- jbyteArray bufferObj = env->NewByteArray(bufferLength);
- if(bufferObj == NULL)
+ jbyteArray bufferObj = newByteArray(env, bufferLength);
+ if(env->ExceptionCheck() || bufferObj == NULL)
{
- LOGE("Error creating byte[] buffer of size: %u", bufferLength);
- return -2;
+ return -105;
}
LOGV("Calling onDataStoreGet(%s, %p)", p, buffer);
int retval = (int)env->CallLongMethod(
ref->dataStoreGetListener,
- dataStoreGetCallbackMethod,
+ DataStoreGetListener_onDataStoreGet_method,
nameStr,
bufferObj);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onDataStoreGet");
+ return -106;
+ }
LOGV("onDataStoreGet returned %d", retval);
if(retval > 0)
{
+ if (retval > bufferLength) {
+ LOGE("retval > bufferLength. retval: %d, bufferLength: %u", retval, bufferLength);
+ return -107;
+ }
+
void *data = env->GetPrimitiveArrayCritical(bufferObj, NULL);
memcpy(buffer, data, retval);
env->ReleasePrimitiveArrayCritical(bufferObj, data, 0);
@@ -496,6 +524,11 @@ namespace {
return retval;
}
+ /**
+ * The function must return zero on success and may return any error code
+ * on failure. Note that success does not (of course) guarantee packet
+ * delivery. It only means that the packet appears to have been sent.
+ */
int WirePacketSendFunction(ZT_Node *node,
void *userData,
void *threadData,
@@ -505,42 +538,51 @@ namespace {
unsigned int bufferSize,
unsigned int ttl)
{
- LOGV("WirePacketSendFunction(%lld, %p, %p, %d)", (long long)localSocket, remoteAddress, buffer, bufferSize);
+ LOGV("WirePacketSendFunction(%" PRId64 ", %p, %p, %u, %u)", localSocket, remoteAddress, buffer, bufferSize, ttl);
JniRef *ref = (JniRef*)userData;
+ assert(ref);
assert(ref->node == node);
- JNIEnv *env = NULL;
- ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
+ JNIEnv *env;
+ GETENV(env, ref->jvm);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Unhandled pending exception");
+ return -100;
+ }
if (ref->packetSender == NULL) {
LOGE("packetSender is NULL");
- return -1;
+ return -101;
}
- jclass packetSenderClass = env->GetObjectClass(ref->packetSender);
- if(packetSenderClass == NULL)
- {
- LOGE("Couldn't find class for PacketSender instance");
- return -1;
+ //
+ // may be NULL
+ //
+ jobject remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
+ if (env->ExceptionCheck()) {
+ return -102;
}
-
- jmethodID packetSenderCallbackMethod = lookup.findMethod(packetSenderClass,
- "onSendPacketRequested", "(JLjava/net/InetSocketAddress;[BI)I");
- if(packetSenderCallbackMethod == NULL)
+ const unsigned char *bytes = static_cast<const unsigned char *>(buffer);
+ jbyteArray bufferObj = newByteArray(env, bytes, bufferSize);
+ if (env->ExceptionCheck() || bufferObj == NULL)
{
- LOGE("Couldn't find onSendPacketRequested method");
- return -2;
+ return -103;
+ }
+
+ int retval = env->CallIntMethod(ref->packetSender, PacketSender_onSendPacketRequested_method, localSocket, remoteAddressObj, bufferObj, 0);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onSendPacketRequested");
+ return -104;
}
-
- jobject remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
- jbyteArray bufferObj = env->NewByteArray(bufferSize);
- env->SetByteArrayRegion(bufferObj, 0, bufferSize, (jbyte*)buffer);
- int retval = env->CallIntMethod(ref->packetSender, packetSenderCallbackMethod, localSocket, remoteAddressObj, bufferObj);
LOGV("JNI Packet Sender returned: %d", retval);
return retval;
}
+ /**
+ * This function must return nonzero (true) if the path should be used.
+ */
int PathCheckFunction(ZT_Node *node,
void *userPtr,
void *threadPtr,
@@ -548,61 +590,44 @@ namespace {
int64_t localSocket,
const struct sockaddr_storage *remoteAddress)
{
+ LOGV("PathCheckFunction");
+
JniRef *ref = (JniRef*)userPtr;
+ assert(ref);
assert(ref->node == node);
if(ref->pathChecker == NULL) {
return true;
}
- JNIEnv *env = NULL;
- ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
+ JNIEnv *env;
+ GETENV(env, ref->jvm);
- jclass pathCheckerClass = env->GetObjectClass(ref->pathChecker);
- if(pathCheckerClass == NULL)
- {
- LOGE("Couldn't find class for PathChecker instance");
- return true;
- }
-
- jmethodID pathCheckCallbackMethod = lookup.findMethod(pathCheckerClass,
- "onPathCheck", "(JJLjava/net/InetSocketAddress;)Z");
- if(pathCheckCallbackMethod == NULL)
- {
- LOGE("Couldn't find onPathCheck method implementation");
+ if (env->ExceptionCheck()) {
+ LOGE("Unhandled pending exception");
return true;
}
//
- // was:
- // struct sockaddr_storage nullAddress = {0};
- //
- // but was getting this warning:
- // warning: suggest braces around initialization of subobject
- //
- // when building ZeroTierOne
- //
- struct sockaddr_storage nullAddress;
-
- //
- // It is possible to assume knowledge about internals of sockaddr_storage and construct
- // correct 0-initializer, but it is simpler to just treat sockaddr_storage as opaque and
- // use memset here to fill with 0
+ // may be NULL
//
- // This is also done in InetAddress.hpp for InetAddress
- //
- memset(&nullAddress, 0, sizeof(sockaddr_storage));
-
- jobject remoteAddressObj = NULL;
+ jobject remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
+ if (env->ExceptionCheck()) {
+ return true;
+ }
- if(memcmp(remoteAddress, &nullAddress, sizeof(sockaddr_storage)) != 0)
- {
- remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
+ jboolean ret = env->CallBooleanMethod(ref->pathChecker, PathChecker_onPathCheck_method, address, localSocket, remoteAddressObj);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling onPathCheck");
+ return true;
}
- return env->CallBooleanMethod(ref->pathChecker, pathCheckCallbackMethod, address, localSocket, remoteAddressObj);
+ return ret;
}
+ /**
+ * It must return a nonzero (true) value if the result buffer has been filled with an address.
+ */
int PathLookupFunction(ZT_Node *node,
void *userPtr,
void *threadPtr,
@@ -610,277 +635,221 @@ namespace {
int ss_family,
struct sockaddr_storage *result)
{
+ LOGV("PathLookupFunction");
+
JniRef *ref = (JniRef*)userPtr;
+ assert(ref);
assert(ref->node == node);
if(ref->pathChecker == NULL) {
return false;
}
- JNIEnv *env = NULL;
- ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
+ JNIEnv *env;
+ GETENV(env, ref->jvm);
- jclass pathCheckerClass = env->GetObjectClass(ref->pathChecker);
- if(pathCheckerClass == NULL)
- {
- LOGE("Couldn't find class for PathChecker instance");
+ if (env->ExceptionCheck()) {
+ LOGE("Unhandled pending exception");
return false;
}
-
- jmethodID pathLookupMethod = lookup.findMethod(pathCheckerClass,
- "onPathLookup", "(JI)Ljava/net/InetSocketAddress;");
- if(pathLookupMethod == NULL) {
+
+ //
+ // may be NULL
+ //
+ jobject sockAddressObject = env->CallObjectMethod(ref->pathChecker, PathChecker_onPathLookup_method, address, ss_family);
+ if (env->ExceptionCheck()) {
+ LOGE("Unable to call onPathLookup implementation");
return false;
}
- jobject sockAddressObject = env->CallObjectMethod(ref->pathChecker, pathLookupMethod, address, ss_family);
if(sockAddressObject == NULL)
{
LOGE("Unable to call onPathLookup implementation");
return false;
}
- jclass inetSockAddressClass = env->GetObjectClass(sockAddressObject);
- if(inetSockAddressClass == NULL)
- {
- LOGE("Unable to find InetSocketAddress class");
+ *result = fromSocketAddressObject(env, sockAddressObject);
+ if (env->ExceptionCheck() || isSocketAddressEmpty(*result)) {
return false;
}
- jmethodID getAddressMethod = lookup.findMethod(inetSockAddressClass, "getAddress", "()Ljava/net/InetAddress;");
- if(getAddressMethod == NULL)
- {
- LOGE("Unable to find InetSocketAddress.getAddress() method");
- return false;
- }
+ return true;
+ }
- jmethodID getPortMethod = lookup.findMethod(inetSockAddressClass, "getPort", "()I");
- if(getPortMethod == NULL)
- {
- LOGE("Unable to find InetSocketAddress.getPort() method");
- return false;
- }
+ typedef std::map<int64_t, JniRef*> NodeMap;
+ NodeMap nodeMap;
+ ZeroTier::Mutex nodeMapMutex;
- jint port = env->CallIntMethod(sockAddressObject, getPortMethod);
- jobject addressObject = env->CallObjectMethod(sockAddressObject, getAddressMethod);
-
- jclass inetAddressClass = lookup.findClass("java/net/InetAddress");
- if(inetAddressClass == NULL)
- {
- LOGE("Unable to find InetAddress class");
- return false;
- }
+ bool isInited(int64_t nodeId) {
- getAddressMethod = lookup.findMethod(inetAddressClass, "getAddress", "()[B");
- if(getAddressMethod == NULL)
- {
- LOGE("Unable to find InetAddress.getAddress() method");
- return false;
- }
+ ZeroTier::Mutex::Lock lock(nodeMapMutex);
+ NodeMap::iterator found = nodeMap.find(nodeId);
- jbyteArray addressBytes = (jbyteArray)env->CallObjectMethod(addressObject, getAddressMethod);
- if(addressBytes == NULL)
- {
- LOGE("Unable to call InetAddress.getBytes()");
+ if (found == nodeMap.end()) {
+
+ //
+ // not in map yet, or has been removed from map
+ //
return false;
}
+
+ JniRef *ref = found->second;
- int addressSize = env->GetArrayLength(addressBytes);
- if(addressSize == 4)
- {
- // IPV4
- sockaddr_in *addr = (sockaddr_in*)result;
- addr->sin_family = AF_INET;
- addr->sin_port = htons(port);
-
- void *data = env->GetPrimitiveArrayCritical(addressBytes, NULL);
- memcpy(&addr->sin_addr, data, 4);
- env->ReleasePrimitiveArrayCritical(addressBytes, data, 0);
- }
- else if (addressSize == 16)
- {
- // IPV6
- sockaddr_in6 *addr = (sockaddr_in6*)result;
- addr->sin6_family = AF_INET6;
- addr->sin6_port = htons(port);
- void *data = env->GetPrimitiveArrayCritical(addressBytes, NULL);
- memcpy(&addr->sin6_addr, data, 16);
- env->ReleasePrimitiveArrayCritical(addressBytes, data, 0);
- }
- else
- {
+ assert(ref);
+
+ return ref->inited;
+ }
+
+ bool JniRef::finishInitializing() {
+
+ ZeroTier::Mutex::Lock lock(nodeMapMutex);
+ NodeMap::iterator found = nodeMap.find(id);
+
+ if (found != nodeMap.end()) {
+ //
+ // already in map
+ //
+ LOGE("Cannot finish initializing; node is already in map");
return false;
}
+ nodeMap.insert(std::make_pair(id, this));
+
+ assert(!inited);
+ inited = true;
+
return true;
}
- typedef std::map<int64_t, JniRef*> NodeMap;
- static NodeMap nodeMap;
- ZeroTier::Mutex nodeMapMutex;
-
ZT_Node* findNode(int64_t nodeId)
{
ZeroTier::Mutex::Lock lock(nodeMapMutex);
NodeMap::iterator found = nodeMap.find(nodeId);
- if(found != nodeMap.end())
- {
- JniRef *ref = found->second;
- return ref->node;
+
+ assert(found != nodeMap.end());
+
+ JniRef *ref = found->second;
+
+ assert(ref);
+
+ return ref->node;
+ }
+
+ JniRef *removeRef(int64_t nodeId) {
+
+ ZeroTier::Mutex::Lock lock(nodeMapMutex);
+
+ NodeMap::iterator found = nodeMap.find(nodeId);
+
+ if (found == nodeMap.end()) {
+ return nullptr;
}
- return NULL;
+
+ JniRef *ref = found->second;
+
+ assert(ref);
+
+ nodeMap.erase(nodeId);
+
+ return ref;
}
}
+#ifdef __cplusplus
+extern "C" {
+#endif
+
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
- lookup.setJavaVM(vm);
+ setupJNICache(vm);
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
{
-
+ teardownJNICache(vm);
}
/*
* Class: com_zerotier_sdk_Node
* Method: node_init
- * Signature: (J)Lcom/zerotier/sdk/ResultCode;
+ * Signature: (JLcom/zerotier/sdk/DataStoreGetListener;Lcom/zerotier/sdk/DataStorePutListener;Lcom/zerotier/sdk/PacketSender;Lcom/zerotier/sdk/EventListener;Lcom/zerotier/sdk/VirtualNetworkFrameListener;Lcom/zerotier/sdk/VirtualNetworkConfigListener;Lcom/zerotier/sdk/PathChecker;)Lcom/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
- JNIEnv *env, jobject obj, jlong now)
+ JNIEnv *env, jobject obj, jlong now, jobject dataStoreGetListener,
+ jobject dataStorePutListener, jobject packetSender, jobject eventListener,
+ jobject frameListener, jobject configListener,
+ jobject pathChecker)
{
LOGV("Creating ZT_Node struct");
- jobject resultObject = createResultObject(env, ZT_RESULT_OK);
+ jobject resultObject = ResultCode_RESULT_OK_enum;
+
+ JavaVM *vm;
+ GETJAVAVM(env, vm);
+
+ assert(dataStoreGetListener != NULL);
+ assert(dataStorePutListener != NULL);
+ assert(packetSender != NULL);
+ assert(frameListener != NULL);
+ assert(configListener != NULL);
+ assert(eventListener != NULL);
+ //
+ // OPTIONAL, pathChecker may be NULL
+ //
+// assert(pathChecker != NULL);
+
+ ZT_Node_Callbacks callbacks{};
+ callbacks.stateGetFunction = &StateGetFunction;
+ callbacks.statePutFunction = &StatePutFunction;
+ callbacks.wirePacketSendFunction = &WirePacketSendFunction;
+ callbacks.virtualNetworkFrameFunction = &VirtualNetworkFrameFunctionCallback;
+ callbacks.virtualNetworkConfigFunction = &VirtualNetworkConfigFunctionCallback;
+ callbacks.eventCallback = &EventCallback;
+ callbacks.pathCheckFunction = &PathCheckFunction;
+ callbacks.pathLookupFunction = &PathLookupFunction;
+
+ //
+ // a bit of a confusing dance here where ref and node both know about each other
+ //
+ JniRef *ref = new JniRef(
+ now,
+ vm,
+ dataStoreGetListener,
+ dataStorePutListener,
+ packetSender,
+ eventListener,
+ frameListener,
+ configListener,
+ pathChecker);
ZT_Node *node;
- JniRef *ref = new JniRef;
- ref->id = (int64_t)now;
- env->GetJavaVM(&ref->jvm);
-
- jclass cls = env->GetObjectClass(obj);
- jfieldID fid = lookup.findField(
- cls, "getListener", "Lcom/zerotier/sdk/DataStoreGetListener;");
-
- if(fid == NULL)
- {
- return NULL; // exception already thrown
- }
-
- jobject tmp = env->GetObjectField(obj, fid);
- if(tmp == NULL)
- {
- return NULL;
- }
- ref->dataStoreGetListener = env->NewGlobalRef(tmp);
-
- fid = lookup.findField(
- cls, "putListener", "Lcom/zerotier/sdk/DataStorePutListener;");
-
- if(fid == NULL)
- {
- return NULL; // exception already thrown
- }
-
- tmp = env->GetObjectField(obj, fid);
- if(tmp == NULL)
- {
- return NULL;
- }
- ref->dataStorePutListener = env->NewGlobalRef(tmp);
-
- fid = lookup.findField(
- cls, "sender", "Lcom/zerotier/sdk/PacketSender;");
- if(fid == NULL)
- {
- return NULL; // exception already thrown
- }
-
- tmp = env->GetObjectField(obj, fid);
- if(tmp == NULL)
- {
- return NULL;
- }
- ref->packetSender = env->NewGlobalRef(tmp);
-
- fid = lookup.findField(
- cls, "frameListener", "Lcom/zerotier/sdk/VirtualNetworkFrameListener;");
- if(fid == NULL)
- {
- return NULL; // exception already thrown
- }
-
- tmp = env->GetObjectField(obj, fid);
- if(tmp == NULL)
- {
- return NULL;
- }
- ref->frameListener = env->NewGlobalRef(tmp);
-
- fid = lookup.findField(
- cls, "configListener", "Lcom/zerotier/sdk/VirtualNetworkConfigListener;");
- if(fid == NULL)
- {
- return NULL; // exception already thrown
- }
-
- tmp = env->GetObjectField(obj, fid);
- if(tmp == NULL)
- {
- return NULL;
- }
- ref->configListener = env->NewGlobalRef(tmp);
-
- fid = lookup.findField(
- cls, "eventListener", "Lcom/zerotier/sdk/EventListener;");
- if(fid == NULL)
- {
- return NULL;
- }
-
- tmp = env->GetObjectField(obj, fid);
- if(tmp == NULL)
- {
- return NULL;
- }
- ref->eventListener = env->NewGlobalRef(tmp);
-
- fid = lookup.findField(
- cls, "pathChecker", "Lcom/zerotier/sdk/PathChecker;");
- if(fid == NULL)
- {
- LOGE("no path checker?");
- return NULL;
- }
-
- tmp = env->GetObjectField(obj, fid);
- if(tmp != NULL)
- {
- ref->pathChecker = env->NewGlobalRef(tmp);
- }
-
- ref->callbacks->stateGetFunction = &StateGetFunction;
- ref->callbacks->statePutFunction = &StatePutFunction;
- ref->callbacks->wirePacketSendFunction = &WirePacketSendFunction;
- ref->callbacks->virtualNetworkFrameFunction = &VirtualNetworkFrameFunctionCallback;
- ref->callbacks->virtualNetworkConfigFunction = &VirtualNetworkConfigFunctionCallback;
- ref->callbacks->eventCallback = &EventCallback;
- ref->callbacks->pathCheckFunction = &PathCheckFunction;
- ref->callbacks->pathLookupFunction = &PathLookupFunction;
-
ZT_ResultCode rc = ZT_Node_new(
&node,
ref,
NULL,
- ref->callbacks,
+ &callbacks,
(int64_t)now);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception creating Node");
+ if(node)
+ {
+ ZT_Node_delete(node);
+ node = NULL;
+ }
+ delete ref;
+ ref = NULL;
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
if(rc != ZT_RESULT_OK)
{
LOGE("Error creating Node: %d", rc);
resultObject = createResultObject(env, rc);
+ if (env->ExceptionCheck() || resultObject == NULL) {
+ return NULL;
+ }
+
if(node)
{
ZT_Node_delete(node);
@@ -891,15 +860,31 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
return resultObject;
}
- ZeroTier::Mutex::Lock lock(nodeMapMutex);
+ //
+ // node is now updated
+ //
ref->node = node;
- nodeMap.insert(std::make_pair(ref->id, ref));
+
+ if (!ref->finishInitializing()) {
+ LOGE("finishInitializing() failed");
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
return resultObject;
}
/*
* Class: com_zerotier_sdk_Node
+ * Method: node_isInited
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_zerotier_sdk_Node_node_1isInited
+ (JNIEnv *env, jobject obj, jlong nodeId) {
+ return isInited(nodeId);
+}
+
+/*
+ * Class: com_zerotier_sdk_Node
* Method: node_delete
* Signature: (J)V
*/
@@ -909,26 +894,15 @@ JNIEXPORT void JNICALL Java_com_zerotier_sdk_Node_node_1delete(
LOGV("Destroying ZT_Node struct");
int64_t nodeId = (int64_t)id;
- NodeMap::iterator found;
- {
- ZeroTier::Mutex::Lock lock(nodeMapMutex);
- found = nodeMap.find(nodeId);
- }
+ JniRef *ref = removeRef(nodeId);
- if(found != nodeMap.end())
- {
- JniRef *ref = found->second;
- nodeMap.erase(found);
+ if (!ref) {
+ return;
+ }
- ZT_Node_delete(ref->node);
+ ZT_Node_delete(ref->node);
- delete ref;
- ref = NULL;
- }
- else
- {
- LOGE("Attempted to delete a node that doesn't exist!");
- }
+ delete ref;
}
/*
@@ -951,17 +925,12 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame(
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline);
if(nbtd_len < 1)
{
// array for next background task length has 0 elements!
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
int64_t now = (int64_t)in_now;
@@ -973,6 +942,9 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame(
unsigned int frameLength = env->GetArrayLength(in_frameData);
void *frameData = env->GetPrimitiveArrayCritical(in_frameData, NULL);
+ //
+ // need local copy of frameData because arbitrary code may run in ZT_Node_processVirtualNetworkFrame and no other JNI work may happen between GetPrimitiveArrayCritical / ReleasePrimitiveArrayCritical
+ //
void *localData = malloc(frameLength);
memcpy(localData, frameData, frameLength);
env->ReleasePrimitiveArrayCritical(in_frameData, frameData, 0);
@@ -991,6 +963,16 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame(
(const void*)localData,
frameLength,
&nextBackgroundTaskDeadline);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling ZT_Node_processVirtualNetworkFrame");
+ free(localData);
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
+ if (rc != ZT_RESULT_OK) {
+ LOGE("ZT_Node_processVirtualNetworkFrame returned: %d", rc);
+ }
+
+ free(localData);
jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
@@ -1002,7 +984,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame(
/*
* Class: com_zerotier_sdk_Node
* Method: processWirePacket
- * Signature: (JJJLjava/net/InetSocketAddress;I[B[J)Lcom/zerotier/sdk/ResultCode;
+ * Signature: (JJJLjava/net/InetSocketAddress;[B[J)Lcom/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
JNIEnv *env, jobject obj,
@@ -1015,122 +997,31 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- LOGE("Couldn't find a valid node!");
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
unsigned int nbtd_len = (unsigned int)env->GetArrayLength(out_nextBackgroundTaskDeadline);
if(nbtd_len < 1)
{
LOGE("nbtd_len < 1");
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
int64_t now = (int64_t)in_now;
- // get the java.net.InetSocketAddress class and getAddress() method
- jclass inetAddressClass = lookup.findClass("java/net/InetAddress");
- if(inetAddressClass == NULL)
- {
- LOGE("Can't find InetAddress class");
- // can't find java.net.InetAddress
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
-
- jmethodID getAddressMethod = lookup.findMethod(
- inetAddressClass, "getAddress", "()[B");
- if(getAddressMethod == NULL)
- {
- // cant find InetAddress.getAddress()
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
-
- jclass InetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress");
- if(InetSocketAddressClass == NULL)
- {
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
-
- jmethodID inetSockGetAddressMethod = lookup.findMethod(
- InetSocketAddressClass, "getAddress", "()Ljava/net/InetAddress;");
-
- jobject remoteAddrObject = env->CallObjectMethod(in_remoteAddress, inetSockGetAddressMethod);
-
- if(remoteAddrObject == NULL)
- {
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
-
- jmethodID inetSock_getPort = lookup.findMethod(
- InetSocketAddressClass, "getPort", "()I");
-
- if(env->ExceptionCheck() || inetSock_getPort == NULL)
- {
- LOGE("Couldn't find getPort method on InetSocketAddress");
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
-
- // call InetSocketAddress.getPort()
- int remotePort = env->CallIntMethod(in_remoteAddress, inetSock_getPort);
- if(env->ExceptionCheck())
- {
- LOGE("Exception calling InetSocketAddress.getPort()");
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
-
- // Call InetAddress.getAddress()
- jbyteArray remoteAddressArray = (jbyteArray)env->CallObjectMethod(remoteAddrObject, getAddressMethod);
- if(remoteAddressArray == NULL)
- {
- LOGE("Unable to call getAddress()");
- // unable to call getAddress()
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
-
- unsigned int addrSize = env->GetArrayLength(remoteAddressArray);
-
-
- // get the address bytes
- jbyte *addr = (jbyte*)env->GetPrimitiveArrayCritical(remoteAddressArray, NULL);
- sockaddr_storage remoteAddress = {};
-
- if(addrSize == 16)
- {
- // IPV6 address
- sockaddr_in6 ipv6 = {};
- ipv6.sin6_family = AF_INET6;
- ipv6.sin6_port = htons(remotePort);
- memcpy(ipv6.sin6_addr.s6_addr, addr, 16);
- memcpy(&remoteAddress, &ipv6, sizeof(sockaddr_in6));
- }
- else if(addrSize == 4)
- {
- // IPV4 address
- sockaddr_in ipv4 = {};
- ipv4.sin_family = AF_INET;
- ipv4.sin_port = htons(remotePort);
- memcpy(&ipv4.sin_addr, addr, 4);
- memcpy(&remoteAddress, &ipv4, sizeof(sockaddr_in));
- }
- else
- {
- LOGE("Unknown IP version");
- // unknown address type
- env->ReleasePrimitiveArrayCritical(remoteAddressArray, addr, 0);
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
+ sockaddr_storage remoteAddress = fromSocketAddressObject(env, in_remoteAddress);
+ if (env->ExceptionCheck() || isSocketAddressEmpty(remoteAddress)) {
+ return NULL;
}
- env->ReleasePrimitiveArrayCritical(remoteAddressArray, addr, 0);
unsigned int packetLength = (unsigned int)env->GetArrayLength(in_packetData);
if(packetLength == 0)
{
LOGE("Empty packet?!?");
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
void *packetData = env->GetPrimitiveArrayCritical(in_packetData, NULL);
+ //
+ // need local copy of packetData because arbitrary code may run in ZT_Node_processWirePacket and no other JNI work may happen between GetPrimitiveArrayCritical / ReleasePrimitiveArrayCritical
+ //
void *localData = malloc(packetLength);
memcpy(localData, packetData, packetLength);
env->ReleasePrimitiveArrayCritical(in_packetData, packetData, 0);
@@ -1146,6 +1037,11 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
localData,
packetLength,
&nextBackgroundTaskDeadline);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling ZT_Node_processWirePacket");
+ free(localData);
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
if(rc != ZT_RESULT_OK)
{
LOGE("ZT_Node_processWirePacket returned: %d", rc);
@@ -1173,22 +1069,24 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processBackgroundTasks(
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline);
if(nbtd_len < 1)
{
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
int64_t now = (int64_t)in_now;
int64_t nextBackgroundTaskDeadline = 0;
ZT_ResultCode rc = ZT_Node_processBackgroundTasks(node, NULL, now, &nextBackgroundTaskDeadline);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling ZT_Node_processBackgroundTasks");
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
+ if (rc != ZT_RESULT_OK) {
+ LOGE("ZT_Node_processBackgroundTasks returned: %d", rc);
+ }
jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
@@ -1207,15 +1105,13 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_join(
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
-
uint64_t nwid = (uint64_t)in_nwid;
ZT_ResultCode rc = ZT_Node_join(node, nwid, NULL, NULL);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling ZT_Node_join");
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
return createResultObject(env, rc);
}
@@ -1230,15 +1126,14 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_leave(
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
uint64_t nwid = (uint64_t)in_nwid;
ZT_ResultCode rc = ZT_Node_leave(node, nwid, NULL, NULL);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling ZT_Node_leave");
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
return createResultObject(env, rc);
}
@@ -1257,11 +1152,6 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastSubscribe(
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
uint64_t nwid = (uint64_t)in_nwid;
uint64_t multicastGroup = (uint64_t)in_multicastGroup;
@@ -1269,6 +1159,10 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastSubscribe(
ZT_ResultCode rc = ZT_Node_multicastSubscribe(
node, NULL, nwid, multicastGroup, multicastAdi);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling ZT_Node_multicastSubscribe");
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
return createResultObject(env, rc);
}
@@ -1287,11 +1181,6 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastUnsubscribe(
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
uint64_t nwid = (uint64_t)in_nwid;
uint64_t multicastGroup = (uint64_t)in_multicastGroup;
@@ -1299,6 +1188,10 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastUnsubscribe(
ZT_ResultCode rc = ZT_Node_multicastUnsubscribe(
node, nwid, multicastGroup, multicastAdi);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling ZT_Node_multicastUnsubscribe");
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
return createResultObject(env, rc);
}
@@ -1316,15 +1209,16 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_orbit(
{
int64_t nodeId = (int64_t)id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
uint64_t moonWorldId = (uint64_t)in_moonWorldId;
uint64_t moonSeed = (uint64_t)in_moonSeed;
ZT_ResultCode rc = ZT_Node_orbit(node, NULL, moonWorldId, moonSeed);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling ZT_Node_orbit");
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
+
return createResultObject(env, rc);
}
@@ -1340,14 +1234,15 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_deorbit(
{
int64_t nodeId = (int64_t)id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
- }
uint64_t moonWorldId = (uint64_t)in_moonWorldId;
ZT_ResultCode rc = ZT_Node_deorbit(node, NULL, moonWorldId);
+ if (env->ExceptionCheck()) {
+ LOGE("Exception calling ZT_Node_deorbit");
+ return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
+ }
+
return createResultObject(env, rc);
}
@@ -1361,11 +1256,6 @@ JNIEXPORT jlong JNICALL Java_com_zerotier_sdk_Node_address(
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return 0;
- }
uint64_t address = ZT_Node_address(node);
return (jlong)address;
@@ -1381,105 +1271,29 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_status
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return 0;
- }
-
- jclass nodeStatusClass = NULL;
- jmethodID nodeStatusConstructor = NULL;
-
- // create a com.zerotier.sdk.NodeStatus object
- nodeStatusClass = lookup.findClass("com/zerotier/sdk/NodeStatus");
- if(nodeStatusClass == NULL)
- {
- return NULL;
- }
-
- nodeStatusConstructor = lookup.findMethod(
- nodeStatusClass, "<init>", "()V");
- if(nodeStatusConstructor == NULL)
- {
- return NULL;
- }
-
- jobject nodeStatusObj = env->NewObject(nodeStatusClass, nodeStatusConstructor);
- if(nodeStatusObj == NULL)
- {
- return NULL;
- }
ZT_NodeStatus nodeStatus;
ZT_Node_status(node, &nodeStatus);
- jfieldID addressField = NULL;
- jfieldID publicIdentityField = NULL;
- jfieldID secretIdentityField = NULL;
- jfieldID onlineField = NULL;
-
- addressField = lookup.findField(nodeStatusClass, "address", "J");
- if(addressField == NULL)
- {
- return NULL;
- }
-
- publicIdentityField = lookup.findField(nodeStatusClass, "publicIdentity", "Ljava/lang/String;");
- if(publicIdentityField == NULL)
- {
- return NULL;
- }
-
- secretIdentityField = lookup.findField(nodeStatusClass, "secretIdentity", "Ljava/lang/String;");
- if(secretIdentityField == NULL)
- {
- return NULL;
- }
-
- onlineField = lookup.findField(nodeStatusClass, "online", "Z");
- if(onlineField == NULL)
- {
- return NULL;
- }
-
- env->SetLongField(nodeStatusObj, addressField, nodeStatus.address);
-
- jstring pubIdentStr = env->NewStringUTF(nodeStatus.publicIdentity);
- if(pubIdentStr == NULL)
- {
- return NULL; // out of memory
- }
- env->SetObjectField(nodeStatusObj, publicIdentityField, pubIdentStr);
-
- jstring secIdentStr = env->NewStringUTF(nodeStatus.secretIdentity);
- if(secIdentStr == NULL)
- {
- return NULL; // out of memory
- }
- env->SetObjectField(nodeStatusObj, secretIdentityField, secIdentStr);
-
- env->SetBooleanField(nodeStatusObj, onlineField, nodeStatus.online);
-
- return nodeStatusObj;
+ return newNodeStatus(env, nodeStatus);
}
/*
* Class: com_zerotier_sdk_Node
* Method: networkConfig
- * Signature: (J)Lcom/zerotier/sdk/VirtualNetworkConfig;
+ * Signature: (JJ)Lcom/zerotier/sdk/VirtualNetworkConfig;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_networkConfig(
JNIEnv *env, jobject obj, jlong id, jlong nwid)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return 0;
- }
ZT_VirtualNetworkConfig *vnetConfig = ZT_Node_networkConfig(node, nwid);
+ if (vnetConfig == NULL) {
+ LOGE("vnetConfig == NULL");
+ return NULL;
+ }
jobject vnetConfigObject = newNetworkConfig(env, *vnetConfig);
@@ -1491,7 +1305,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_networkConfig(
/*
* Class: com_zerotier_sdk_Node
* Method: version
- * Signature: (J)Lcom/zerotier/sdk/Version;
+ * Signature: ()Lcom/zerotier/sdk/Version;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_version(
JNIEnv *env, jobject obj)
@@ -1515,11 +1329,6 @@ JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers(
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return 0;
- }
ZT_PeerList *peerList = ZT_Node_peers(node);
@@ -1529,44 +1338,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers(
return NULL;
}
- int peerCount = peerList->peerCount * 100;
- LOGV("Ensure Local Capacity: %d", peerCount);
- if(env->EnsureLocalCapacity(peerCount))
- {
- LOGE("EnsureLocalCapacity failed!!");
- ZT_Node_freeQueryResult(node, peerList);
- return NULL;
- }
-
- jclass peerClass = lookup.findClass("com/zerotier/sdk/Peer");
- if(env->ExceptionCheck() || peerClass == NULL)
- {
- LOGE("Error finding Peer class");
- ZT_Node_freeQueryResult(node, peerList);
- return NULL;
- }
-
- jobjectArray peerArrayObj = env->NewObjectArray(
- peerList->peerCount, peerClass, NULL);
-
- if(env->ExceptionCheck() || peerArrayObj == NULL)
- {
- LOGE("Error creating Peer[] array");
- ZT_Node_freeQueryResult(node, peerList);
- return NULL;
- }
-
-
- for(unsigned int i = 0; i < peerList->peerCount; ++i)
- {
- jobject peerObj = newPeer(env, peerList->peers[i]);
- env->SetObjectArrayElement(peerArrayObj, i, peerObj);
- if(env->ExceptionCheck())
- {
- LOGE("Error assigning Peer object to array");
- break;
- }
- }
+ jobjectArray peerArrayObj = newPeerArray(env, peerList->peers, peerList->peerCount);
ZT_Node_freeQueryResult(node, peerList);
peerList = NULL;
@@ -1576,53 +1348,23 @@ JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers(
/*
* Class: com_zerotier_sdk_Node
- * Method: networks
+ * Method: networkConfigs
* Signature: (J)[Lcom/zerotier/sdk/VirtualNetworkConfig;
*/
-JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networks(
+JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networkConfigs(
JNIEnv *env, jobject obj, jlong id)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
- if(node == NULL)
- {
- // cannot find valid node. We should never get here.
- return 0;
- }
ZT_VirtualNetworkList *networkList = ZT_Node_networks(node);
if(networkList == NULL)
{
+ LOGE("ZT_Node_networks returned NULL");
return NULL;
}
- jclass vnetConfigClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfig");
- if(env->ExceptionCheck() || vnetConfigClass == NULL)
- {
- LOGE("Error finding VirtualNetworkConfig class");
- ZT_Node_freeQueryResult(node, networkList);
- return NULL;
- }
-
- jobjectArray networkListObject = env->NewObjectArray(
- networkList->networkCount, vnetConfigClass, NULL);
- if(env->ExceptionCheck() || networkListObject == NULL)
- {
- LOGE("Error creating VirtualNetworkConfig[] array");
- ZT_Node_freeQueryResult(node, networkList);
- return NULL;
- }
-
- for(unsigned int i = 0; i < networkList->networkCount; ++i)
- {
- jobject networkObject = newNetworkConfig(env, networkList->networks[i]);
- env->SetObjectArrayElement(networkListObject, i, networkObject);
- if(env->ExceptionCheck())
- {
- LOGE("Error assigning VirtualNetworkConfig object to array");
- break;
- }
- }
+ jobjectArray networkListObject = newVirtualNetworkConfigArray(env, networkList->networks, networkList->networkCount);
ZT_Node_freeQueryResult(node, networkList);
@@ -1631,4 +1373,4 @@ JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networks(
#ifdef __cplusplus
} // extern "C"
-#endif \ No newline at end of file
+#endif
diff --git a/java/jni/com_zerotierone_sdk_Node.h b/java/jni/com_zerotierone_sdk_Node.h
index 8487d8af..a439f412 100644
--- a/java/jni/com_zerotierone_sdk_Node.h
+++ b/java/jni/com_zerotierone_sdk_Node.h
@@ -10,9 +10,17 @@ extern "C" {
/*
* Class: com_zerotier_sdk_Node
* Method: node_init
- * Signature: (J)Lcom/zerotier/sdk/ResultCode;
+ * Signature: (JLcom/zerotier/sdk/DataStoreGetListener;Lcom/zerotier/sdk/DataStorePutListener;Lcom/zerotier/sdk/PacketSender;Lcom/zerotier/sdk/EventListener;Lcom/zerotier/sdk/VirtualNetworkFrameListener;Lcom/zerotier/sdk/VirtualNetworkConfigListener;Lcom/zerotier/sdk/PathChecker;)Lcom/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init
+ (JNIEnv *, jobject, jlong, jobject, jobject, jobject, jobject, jobject, jobject, jobject);
+
+/*
+ * Class: com_zerotier_sdk_Node
+ * Method: node_isInited
+ * Signature: (J)Z;
+ */
+JNIEXPORT jboolean JNICALL Java_com_zerotier_sdk_Node_node_1isInited
(JNIEnv *, jobject, jlong);
/*
@@ -34,7 +42,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame
/*
* Class: com_zerotier_sdk_Node
* Method: processWirePacket
- * Signature: (JJLjava/net/InetSockAddress;Ljava/net/InetSockAddress;[B[J)Lcom/zerotier/sdk/ResultCode;
+ * Signature: (JJJLjava/net/InetSockAddress;[B[J)Lcom/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket
(JNIEnv *, jobject, jlong, jlong, jlong, jobject, jbyteArray, jlongArray);
@@ -121,10 +129,10 @@ JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers
/*
* Class: com_zerotier_sdk_Node
- * Method: networks
+ * Method: networkConfigs
* Signature: (J)[Lcom/zerotier/sdk/VirtualNetworkConfig;
*/
-JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networks
+JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networkConfigs
(JNIEnv *, jobject, jlong);
#ifdef __cplusplus
diff --git a/java/src/com/zerotier/sdk/DataStoreGetListener.java b/java/src/com/zerotier/sdk/DataStoreGetListener.java
index 317511e0..105b14c5 100644
--- a/java/src/com/zerotier/sdk/DataStoreGetListener.java
+++ b/java/src/com/zerotier/sdk/DataStoreGetListener.java
@@ -24,6 +24,7 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
public interface DataStoreGetListener {
@@ -48,7 +49,7 @@ public interface DataStoreGetListener {
* @param out_buffer buffer to put the object in
* @return size of the object
*/
- public long onDataStoreGet(
+ long onDataStoreGet(
String name,
byte[] out_buffer);
}
diff --git a/java/src/com/zerotier/sdk/DataStorePutListener.java b/java/src/com/zerotier/sdk/DataStorePutListener.java
index 77e55027..0fa8e19c 100644
--- a/java/src/com/zerotier/sdk/DataStorePutListener.java
+++ b/java/src/com/zerotier/sdk/DataStorePutListener.java
@@ -24,6 +24,7 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
public interface DataStorePutListener {
@@ -43,7 +44,7 @@ public interface DataStorePutListener {
* @param secure set to user read/write only.
* @return 0 on success.
*/
- public int onDataStorePut(
+ int onDataStorePut(
String name,
byte[] buffer,
boolean secure);
@@ -54,6 +55,6 @@ public interface DataStorePutListener {
* @param name Object name
* @return 0 on success.
*/
- public int onDelete(
+ int onDelete(
String name);
}
diff --git a/java/src/com/zerotier/sdk/Event.java b/java/src/com/zerotier/sdk/Event.java
index 22d350e1..fbc016c6 100644
--- a/java/src/com/zerotier/sdk/Event.java
+++ b/java/src/com/zerotier/sdk/Event.java
@@ -27,26 +27,32 @@
package com.zerotier.sdk;
+/**
+ * Status codes sent to status update callback when things happen
+ *
+ * Defined in ZeroTierOne.h as ZT_Event
+ */
public enum Event {
+
/**
* Node has been initialized
*
* This is the first event generated, and is always sent. It may occur
* before Node's constructor returns.
*/
- EVENT_UP,
+ EVENT_UP(0),
/**
* Node is offline -- network does not seem to be reachable by any available strategy
*/
- EVENT_OFFLINE,
+ EVENT_OFFLINE(1),
/**
* Node is online -- at least one upstream node appears reachable
*
* Meta-data: none
*/
- EVENT_ONLINE,
+ EVENT_ONLINE(2),
/**
* Node is shutting down
@@ -55,7 +61,7 @@ public enum Event {
* It's done for convenience, since cleaning up other state in the event
* handler may appear more idiomatic.</p>
*/
- EVENT_DOWN,
+ EVENT_DOWN(3),
/**
* Your identity has collided with another node's ZeroTier address
@@ -85,7 +91,7 @@ public enum Event {
* condition is a good way to make sure it never arises. It's like how
* umbrellas prevent rain and smoke detectors prevent fires. They do, right?</p>
*/
- EVENT_FATAL_ERROR_IDENTITY_COLLISION,
+ EVENT_FATAL_ERROR_IDENTITY_COLLISION(4),
/**
* Trace (debugging) message
@@ -94,5 +100,55 @@ public enum Event {
*
* <p>Meta-data: {@link String}, TRACE message</p>
*/
- EVENT_TRACE
-} \ No newline at end of file
+ EVENT_TRACE(5),
+
+ /**
+ * VERB_USER_MESSAGE received
+ *
+ * These are generated when a VERB_USER_MESSAGE packet is received via
+ * ZeroTier VL1.
+ */
+ EVENT_USER_MESSAGE(6),
+
+ /**
+ * Remote trace received
+ *
+ * These are generated when a VERB_REMOTE_TRACE is received. Note
+ * that any node can fling one of these at us. It is your responsibility
+ * to filter and determine if it's worth paying attention to. If it's
+ * not just drop it. Most nodes that are not active controllers ignore
+ * these, and controllers only save them if they pertain to networks
+ * with remote tracing enabled.
+ */
+ EVENT_REMOTE_TRACE(7);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ Event(int id) {
+ this.id = id;
+ }
+
+ public static Event fromInt(int id) {
+ switch (id) {
+ case 0:
+ return EVENT_UP;
+ case 1:
+ return EVENT_OFFLINE;
+ case 2:
+ return EVENT_ONLINE;
+ case 3:
+ return EVENT_DOWN;
+ case 4:
+ return EVENT_FATAL_ERROR_IDENTITY_COLLISION;
+ case 5:
+ return EVENT_TRACE;
+ case 6:
+ return EVENT_USER_MESSAGE;
+ case 7:
+ return EVENT_REMOTE_TRACE;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
+}
diff --git a/java/src/com/zerotier/sdk/EventListener.java b/java/src/com/zerotier/sdk/EventListener.java
index 91050aaa..88fb8afc 100644
--- a/java/src/com/zerotier/sdk/EventListener.java
+++ b/java/src/com/zerotier/sdk/EventListener.java
@@ -27,19 +27,17 @@
package com.zerotier.sdk;
-import java.net.InetSocketAddress;
-import java.lang.String;
-
/**
* Interface to handle callbacks for ZeroTier One events.
*/
public interface EventListener {
+
/**
* Callback for events with no other associated metadata
*
* @param event {@link Event} enum
*/
- public void onEvent(Event event);
+ void onEvent(Event event);
/**
* Trace messages
@@ -48,5 +46,5 @@ public interface EventListener {
*
* @param message the trace message
*/
- public void onTrace(String message);
+ void onTrace(String message);
}
diff --git a/java/src/com/zerotier/sdk/NativeUtils.java b/java/src/com/zerotier/sdk/NativeUtils.java
deleted file mode 100644
index 4932a6c7..00000000
--- a/java/src/com/zerotier/sdk/NativeUtils.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.zerotier.sdk;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Simple library class for working with JNI (Java Native Interface)
- *
- * @see http://adamheinrich.com/2012/how-to-load-native-jni-library-from-jar
- *
- * @author Adam Heirnich <[email protected]>, http://www.adamh.cz
- */
-public class NativeUtils {
-
- /**
- * Private constructor - this class will never be instanced
- */
- private NativeUtils() {
- }
-
- /**
- * Loads library from current JAR archive
- *
- * The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after exiting.
- * Method uses String as filename because the pathname is "abstract", not system-dependent.
- *
- * @param filename The filename inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext
- * @throws IOException If temporary file creation or read/write operation fails
- * @throws IllegalArgumentException If source file (param path) does not exist
- * @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of {@see File#createTempFile(java.lang.String, java.lang.String)}).
- */
- public static void loadLibraryFromJar(String path) throws IOException {
-
- if (!path.startsWith("/")) {
- throw new IllegalArgumentException("The path has to be absolute (start with '/').");
- }
-
- // Obtain filename from path
- String[] parts = path.split("/");
- String filename = (parts.length > 1) ? parts[parts.length - 1] : null;
-
- // Split filename to prefix and suffix (extension)
- String prefix = "";
- String suffix = null;
- if (filename != null) {
- parts = filename.split("\\.", 2);
- prefix = parts[0];
- suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; // Thanks, davs! :-)
- }
-
- // Check if the filename is okay
- if (filename == null || prefix.length() < 3) {
- throw new IllegalArgumentException("The filename has to be at least 3 characters long.");
- }
-
- // Prepare temporary file
- File temp = File.createTempFile(prefix, suffix);
- temp.deleteOnExit();
-
- if (!temp.exists()) {
- throw new FileNotFoundException("File " + temp.getAbsolutePath() + " does not exist.");
- }
-
- // Prepare buffer for data copying
- byte[] buffer = new byte[1024];
- int readBytes;
-
- // Open and check input stream
- InputStream is = NativeUtils.class.getResourceAsStream(path);
- if (is == null) {
- throw new FileNotFoundException("File " + path + " was not found inside JAR.");
- }
-
- // Open output stream and copy data between source file in JAR and the temporary file
- OutputStream os = new FileOutputStream(temp);
- try {
- while ((readBytes = is.read(buffer)) != -1) {
- os.write(buffer, 0, readBytes);
- }
- } finally {
- // If read/write fails, close streams safely before throwing an exception
- os.close();
- is.close();
- }
-
- // Finally, load the library
- System.load(temp.getAbsolutePath());
- }
-} \ No newline at end of file
diff --git a/java/src/com/zerotier/sdk/Node.java b/java/src/com/zerotier/sdk/Node.java
index 1b3a4901..a3f3ab47 100644
--- a/java/src/com/zerotier/sdk/Node.java
+++ b/java/src/com/zerotier/sdk/Node.java
@@ -28,95 +28,72 @@
package com.zerotier.sdk;
import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.io.IOException;
/**
* A ZeroTier One node
*/
public class Node {
- static {
- try {
- System.loadLibrary("ZeroTierOneJNI");
- } catch (UnsatisfiedLinkError e) {
- try {
- if(System.getProperty("os.name").startsWith("Windows")) {
- System.out.println("Arch: " + System.getProperty("sun.arch.data.model"));
- if(System.getProperty("sun.arch.data.model").equals("64")) {
- NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win64.dll");
- } else {
- NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win32.dll");
- }
- } else if(System.getProperty("os.name").startsWith("Mac")) {
- NativeUtils.loadLibraryFromJar("/lib/libZeroTierOneJNI.jnilib");
- } else {
- // TODO: Linux
- }
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- }
+ static {
+ System.loadLibrary("ZeroTierOneJNI");
+ }
private static final String TAG = "NODE";
/**
* Node ID for JNI purposes.
* Currently set to the now value passed in at the constructor
- *
- * -1 if the node has already been closed
*/
- private long nodeId;
-
- private final DataStoreGetListener getListener;
- private final DataStorePutListener putListener;
- private final PacketSender sender;
- private final EventListener eventListener;
- private final VirtualNetworkFrameListener frameListener;
- private final VirtualNetworkConfigListener configListener;
- private final PathChecker pathChecker;
+ private final long nodeId;
/**
* Create a new ZeroTier One node
*
+ * @param now Current clock in milliseconds
+ */
+ public Node(long now) {
+ this.nodeId = now;
+ }
+
+ /**
+ * Init a new ZeroTier One node
+ *
* <p>Note that this can take a few seconds the first time it's called, as it
* will generate an identity.</p>
*
- * @param now Current clock in milliseconds
* @param getListener User written instance of the {@link DataStoreGetListener} interface called to get objects from persistent storage. This instance must be unique per Node object.
* @param putListener User written instance of the {@link DataStorePutListener} interface called to put objects in persistent storage. This instance must be unique per Node object.
- * @param sender
+ * @param sender User written instance of the {@link PacketSender} interface to send ZeroTier packets out over the wire.
* @param eventListener User written instance of the {@link EventListener} interface to receive status updates and non-fatal error notices. This instance must be unique per Node object.
- * @param frameListener
+ * @param frameListener User written instance of the {@link VirtualNetworkFrameListener} interface to send a frame out to a virtual network port.
* @param configListener User written instance of the {@link VirtualNetworkConfigListener} interface to be called when virtual LANs are created, deleted, or their config parameters change. This instance must be unique per Node object.
* @param pathChecker User written instance of the {@link PathChecker} interface. Not required and can be null.
*/
- public Node(long now,
- DataStoreGetListener getListener,
- DataStorePutListener putListener,
- PacketSender sender,
- EventListener eventListener,
- VirtualNetworkFrameListener frameListener,
- VirtualNetworkConfigListener configListener,
- PathChecker pathChecker) throws NodeException
- {
- this.nodeId = now;
-
- this.getListener = getListener;
- this.putListener = putListener;
- this.sender = sender;
- this.eventListener = eventListener;
- this.frameListener = frameListener;
- this.configListener = configListener;
- this.pathChecker = pathChecker;
-
- ResultCode rc = node_init(now);
- if(rc != ResultCode.RESULT_OK)
- {
- // TODO: Throw Exception
+ public ResultCode init(
+ DataStoreGetListener getListener,
+ DataStorePutListener putListener,
+ PacketSender sender,
+ EventListener eventListener,
+ VirtualNetworkFrameListener frameListener,
+ VirtualNetworkConfigListener configListener,
+ PathChecker pathChecker) throws NodeException {
+ ResultCode rc = node_init(
+ nodeId,
+ getListener,
+ putListener,
+ sender,
+ eventListener,
+ frameListener,
+ configListener,
+ pathChecker);
+ if(rc != ResultCode.RESULT_OK) {
throw new NodeException(rc.toString());
}
- }
+ return rc;
+ }
+
+ public boolean isInited() {
+ return node_isInited(nodeId);
+ }
/**
* Close this Node.
@@ -124,15 +101,12 @@ public class Node {
* <p>The Node object can no longer be used once this method is called.</p>
*/
public void close() {
- if(nodeId != -1) {
- node_delete(nodeId);
- nodeId = -1;
- }
+ node_delete(nodeId);
}
@Override
- protected void finalize() {
- close();
+ public String toString() {
+ return "Node(" + nodeId + ")";
}
/**
@@ -166,6 +140,7 @@ public class Node {
* Process a packet received from the physical wire
*
* @param now Current clock in milliseconds
+ * @param localSocket Local socket or -1
* @param remoteAddress Origin of packet
* @param packetData Packet data
* @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
@@ -392,8 +367,8 @@ public class Node {
*
* @return List of networks or NULL on failure
*/
- public VirtualNetworkConfig[] networks() {
- return networks(nodeId);
+ public VirtualNetworkConfig[] networkConfigs() {
+ return networkConfigs(nodeId);
}
/**
@@ -408,7 +383,17 @@ public class Node {
//
// function declarations for JNI
//
- private native ResultCode node_init(long now);
+ private native ResultCode node_init(
+ long nodeId,
+ DataStoreGetListener dataStoreGetListener,
+ DataStorePutListener dataStorePutListener,
+ PacketSender packetSender,
+ EventListener eventListener,
+ VirtualNetworkFrameListener virtualNetworkFrameListener,
+ VirtualNetworkConfigListener virtualNetworkConfigListener,
+ PathChecker pathChecker);
+
+ private native boolean node_isInited(long nodeId);
private native void node_delete(long nodeId);
@@ -471,5 +456,5 @@ public class Node {
private native Peer[] peers(long nodeId);
- private native VirtualNetworkConfig[] networks(long nodeId);
-} \ No newline at end of file
+ private native VirtualNetworkConfig[] networkConfigs(long nodeId);
+}
diff --git a/java/src/com/zerotier/sdk/NodeException.java b/java/src/com/zerotier/sdk/NodeException.java
index 1fdef72f..beeb0606 100644
--- a/java/src/com/zerotier/sdk/NodeException.java
+++ b/java/src/com/zerotier/sdk/NodeException.java
@@ -27,10 +27,11 @@
package com.zerotier.sdk;
-import java.lang.RuntimeException;
+public class NodeException extends Exception {
-public class NodeException extends RuntimeException {
+ private static final long serialVersionUID = 6268040509883125819L;
+
public NodeException(String message) {
super(message);
}
-} \ No newline at end of file
+}
diff --git a/java/src/com/zerotier/sdk/NodeStatus.java b/java/src/com/zerotier/sdk/NodeStatus.java
index 11e49ade..1172650b 100644
--- a/java/src/com/zerotier/sdk/NodeStatus.java
+++ b/java/src/com/zerotier/sdk/NodeStatus.java
@@ -27,43 +27,64 @@
package com.zerotier.sdk;
-public final class NodeStatus {
- private long address;
- private String publicIdentity;
- private String secretIdentity;
- private boolean online;
+import com.zerotier.sdk.util.StringUtils;
- private NodeStatus() {}
+/**
+ * Current node status
+ *
+ * Defined in ZeroTierOne.h as ZT_NodeStatus
+ */
+public class NodeStatus {
+
+ private final long address;
+
+ private final String publicIdentity;
+
+ private final String secretIdentity;
+
+ private final boolean online;
+
+ public NodeStatus(long address, String publicIdentity, String secretIdentity, boolean online) {
+ this.address = address;
+ this.publicIdentity = publicIdentity;
+ this.secretIdentity = secretIdentity;
+ this.online = online;
+ }
+
+ @Override
+ public String toString() {
+ return "NodeStatus(" + StringUtils.addressToString(address) + ", " + publicIdentity + ", " + secretIdentity + ", " + online + ")";
+ }
/**
* 40-bit ZeroTier address of this node
*/
- public final long getAddress() {
- return address;
- }
+ public long getAddress() {
+ return address;
+ }
/**
* Public identity in string-serialized form (safe to send to others)
*
* <p>This identity will remain valid as long as the node exists.</p>
*/
- public final String getPublicIdentity() {
- return publicIdentity;
- }
+ public String getPublicIdentity() {
+ return publicIdentity;
+ }
/**
* Full identity including secret key in string-serialized form
*
* <p>This identity will remain valid as long as the node exists.</p>
*/
- public final String getSecretIdentity() {
- return secretIdentity;
- }
+ public String getSecretIdentity() {
+ return secretIdentity;
+ }
/**
* True if some kind of connectivity appears available
*/
- public final boolean isOnline() {
- return online;
- }
-} \ No newline at end of file
+ public boolean isOnline() {
+ return online;
+ }
+}
diff --git a/java/src/com/zerotier/sdk/PacketSender.java b/java/src/com/zerotier/sdk/PacketSender.java
index 06ec01bc..893824a0 100644
--- a/java/src/com/zerotier/sdk/PacketSender.java
+++ b/java/src/com/zerotier/sdk/PacketSender.java
@@ -24,12 +24,14 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
import java.net.InetSocketAddress;
public interface PacketSender {
+
/**
* Function to send a ZeroTier packet out over the wire
*
@@ -40,9 +42,10 @@ public interface PacketSender {
* @param localSocket socket file descriptor to send from. Set to -1 if not specified.
* @param remoteAddr {@link InetSocketAddress} to send to
* @param packetData data to send
+ * @param ttl TTL is ignored
* @return 0 on success, any error code on failure.
*/
- public int onSendPacketRequested(
+ int onSendPacketRequested(
long localSocket,
InetSocketAddress remoteAddr,
byte[] packetData,
diff --git a/java/src/com/zerotier/sdk/PathChecker.java b/java/src/com/zerotier/sdk/PathChecker.java
index 6bf31df2..cfc97d60 100644
--- a/java/src/com/zerotier/sdk/PathChecker.java
+++ b/java/src/com/zerotier/sdk/PathChecker.java
@@ -8,6 +8,7 @@ package com.zerotier.sdk;
import java.net.InetSocketAddress;
public interface PathChecker {
+
/**
* Callback to check whether a path should be used for ZeroTier traffic
*
@@ -28,6 +29,7 @@ public interface PathChecker {
* @param ztAddress ZeroTier address or 0 for none/any
* @param localSocket Local interface socket. -1 if unspecified
* @param remoteAddress remote address
+ * @return true if the path should be used
*/
boolean onPathCheck(long ztAddress, long localSocket, InetSocketAddress remoteAddress);
diff --git a/java/src/com/zerotier/sdk/Peer.java b/java/src/com/zerotier/sdk/Peer.java
index eb3d7130..e3d54438 100644
--- a/java/src/com/zerotier/sdk/Peer.java
+++ b/java/src/com/zerotier/sdk/Peer.java
@@ -27,68 +27,92 @@
package com.zerotier.sdk;
-import java.util.ArrayList;
+import com.zerotier.sdk.util.StringUtils;
+
+import java.util.Arrays;
/**
- * Peer status result
+ * Peer status result buffer
+ *
+ * Defined in ZeroTierOne.h as ZT_Peer
*/
-public final class Peer {
- private long address;
- private int versionMajor;
- private int versionMinor;
- private int versionRev;
- private int latency;
- private PeerRole role;
- private PeerPhysicalPath[] paths;
+public class Peer {
+
+ private final long address;
+
+ private final int versionMajor;
+
+ private final int versionMinor;
+
+ private final int versionRev;
- private Peer() {}
+ private final int latency;
+
+ private final PeerRole role;
+
+ private final PeerPhysicalPath[] paths;
+
+ public Peer(long address, int versionMajor, int versionMinor, int versionRev, int latency, PeerRole role, PeerPhysicalPath[] paths) {
+ this.address = address;
+ this.versionMajor = versionMajor;
+ this.versionMinor = versionMinor;
+ this.versionRev = versionRev;
+ this.latency = latency;
+ this.role = role;
+ this.paths = paths;
+ }
+
+ @Override
+ public String toString() {
+ return "Peer(" + StringUtils.addressToString(address) + ", " + versionMajor + ", " + versionMinor + ", " + versionRev + ", " + latency + ", " + role + ", " + Arrays.toString(paths) + ")";
+ }
/**
* ZeroTier address (40 bits)
*/
- public final long address() {
+ public long getAddress() {
return address;
}
/**
* Remote major version or -1 if not known
*/
- public final int versionMajor() {
+ public int getVersionMajor() {
return versionMajor;
}
/**
* Remote minor version or -1 if not known
*/
- public final int versionMinor() {
+ public int getVersionMinor() {
return versionMinor;
}
/**
* Remote revision or -1 if not known
*/
- public final int versionRev() {
+ public int getVersionRev() {
return versionRev;
}
/**
* Last measured latency in milliseconds or zero if unknown
*/
- public final int latency() {
+ public int getLatency() {
return latency;
}
/**
* What trust hierarchy role does this device have?
*/
- public final PeerRole role() {
+ public PeerRole getRole() {
return role;
}
/**
* Known network paths to peer
*/
- public final PeerPhysicalPath[] paths() {
+ public PeerPhysicalPath[] getPaths() {
return paths;
}
-} \ No newline at end of file
+}
diff --git a/java/src/com/zerotier/sdk/PeerPhysicalPath.java b/java/src/com/zerotier/sdk/PeerPhysicalPath.java
index 3f9a8612..f6d32642 100644
--- a/java/src/com/zerotier/sdk/PeerPhysicalPath.java
+++ b/java/src/com/zerotier/sdk/PeerPhysicalPath.java
@@ -31,48 +31,62 @@ import java.net.InetSocketAddress;
/**
* Physical network path to a peer
+ *
+ * Defined in ZeroTierOne.h as ZT_PeerPhysicalPath
*/
-public final class PeerPhysicalPath {
- private InetSocketAddress address;
- private long lastSend;
- private long lastReceive;
- private boolean fixed;
- private boolean preferred;
+public class PeerPhysicalPath {
+
+ private final InetSocketAddress address;
+
+ private final long lastSend;
+
+ private final long lastReceive;
+
+ private final boolean preferred;
+
+ public PeerPhysicalPath(InetSocketAddress address, long lastSend, long lastReceive, boolean preferred) {
+ this.address = address;
+ if (lastSend < 0) {
+ throw new RuntimeException("lastSend < 0: " + lastSend);
+ }
+ this.lastSend = lastSend;
+ if (lastReceive < 0) {
+ throw new RuntimeException("lastReceive < 0: " + lastReceive);
+ }
+ this.lastReceive = lastReceive;
+ this.preferred = preferred;
+ }
- private PeerPhysicalPath() {}
+ @Override
+ public String toString() {
+ return "PeerPhysicalPath(" + address + ", " + lastSend + ", " + lastReceive + ", " + preferred + ")";
+ }
/**
* Address of endpoint
*/
- public final InetSocketAddress address() {
+ public InetSocketAddress getAddress() {
return address;
}
/**
* Time of last send in milliseconds or 0 for never
*/
- public final long lastSend() {
+ public long getLastSend() {
return lastSend;
}
/**
* Time of last receive in milliseconds or 0 for never
*/
- public final long lastReceive() {
+ public long getLastReceive() {
return lastReceive;
}
/**
- * Is path fixed? (i.e. not learned, static)
- */
- public final boolean isFixed() {
- return fixed;
- }
-
- /**
* Is path preferred?
*/
- public final boolean isPreferred() {
+ public boolean isPreferred() {
return preferred;
}
-} \ No newline at end of file
+}
diff --git a/java/src/com/zerotier/sdk/PeerRole.java b/java/src/com/zerotier/sdk/PeerRole.java
index fce183d9..d69a1f1b 100644
--- a/java/src/com/zerotier/sdk/PeerRole.java
+++ b/java/src/com/zerotier/sdk/PeerRole.java
@@ -27,19 +27,45 @@
package com.zerotier.sdk;
+/**
+ * What trust hierarchy role does this peer have?
+ *
+ * Defined in ZeroTierOne.h as ZT_PeerRole
+ */
public enum PeerRole {
+
/**
* An ordinary node
*/
- PEER_ROLE_LEAF,
+ PEER_ROLE_LEAF(0),
/**
* moon root
*/
- PEER_ROLE_MOON,
+ PEER_ROLE_MOON(1),
/**
* planetary root
*/
- PEER_ROLE_PLANET
-} \ No newline at end of file
+ PEER_ROLE_PLANET(2);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ PeerRole(int id) {
+ this.id = id;
+ }
+
+ public static PeerRole fromInt(int id) {
+ switch (id) {
+ case 0:
+ return PEER_ROLE_LEAF;
+ case 1:
+ return PEER_ROLE_MOON;
+ case 2:
+ return PEER_ROLE_PLANET;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
+}
diff --git a/java/src/com/zerotier/sdk/ResultCode.java b/java/src/com/zerotier/sdk/ResultCode.java
index 09e7d3b1..dc8a901b 100644
--- a/java/src/com/zerotier/sdk/ResultCode.java
+++ b/java/src/com/zerotier/sdk/ResultCode.java
@@ -34,12 +34,20 @@ package com.zerotier.sdk;
* occurs, the node should be considered to not be working correctly. These
* indicate serious problems like an inaccessible data store or a compile
* problem.</p>
+ *
+ * Defined in ZeroTierOne.h as ZT_ResultCode
*/
public enum ResultCode {
+
/**
* Operation completed normally
*/
- RESULT_OK(0),
+ RESULT_OK(0),
+
+ /**
+ * Call produced no error but no action was taken
+ */
+ RESULT_OK_IGNORED(1),
// Fatal errors (>=100, <1000)
/**
@@ -68,12 +76,36 @@ public enum ResultCode {
RESULT_ERROR_BAD_PARAMETER(1002);
-
- private final int id;
- ResultCode(int id) { this.id = id; }
- public int getValue() { return id; }
+ private final int id;
+
+ ResultCode(int id) {
+ this.id = id;
+ }
+
+ public static ResultCode fromInt(int id) {
+ switch (id) {
+ case 0:
+ return RESULT_OK;
+ case 1:
+ return RESULT_OK_IGNORED;
+ case 100:
+ return RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ case 101:
+ return RESULT_FATAL_ERROR_DATA_STORE_FAILED;
+ case 102:
+ return RESULT_FATAL_ERROR_INTERNAL;
+ case 1000:
+ return RESULT_ERROR_NETWORK_NOT_FOUND;
+ case 1001:
+ return RESULT_ERROR_UNSUPPORTED_OPERATION;
+ case 1002:
+ return RESULT_ERROR_BAD_PARAMETER;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
- public boolean isFatal(int id) {
- return (id > 100 && id < 1000);
+ public boolean isFatal() {
+ return (id >= 100 && id < 1000);
}
-} \ No newline at end of file
+}
diff --git a/java/src/com/zerotier/sdk/Version.java b/java/src/com/zerotier/sdk/Version.java
index c93c2597..0dbe1d2a 100644
--- a/java/src/com/zerotier/sdk/Version.java
+++ b/java/src/com/zerotier/sdk/Version.java
@@ -27,10 +27,27 @@
package com.zerotier.sdk;
-public final class Version {
- private Version() {}
-
- public int major = 0;
- public int minor = 0;
- public int revision = 0;
-} \ No newline at end of file
+public class Version {
+
+ private final int major;
+ private final int minor;
+ private final int revision;
+
+ public Version(int major, int minor, int revision) {
+ this.major = major;
+ this.minor = minor;
+ this.revision = revision;
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public int getRevision() {
+ return revision;
+ }
+}
diff --git a/java/src/com/zerotier/sdk/VirtualNetworkConfig.java b/java/src/com/zerotier/sdk/VirtualNetworkConfig.java
index c7b48d5c..fea354d0 100644
--- a/java/src/com/zerotier/sdk/VirtualNetworkConfig.java
+++ b/java/src/com/zerotier/sdk/VirtualNetworkConfig.java
@@ -29,197 +29,305 @@ package com.zerotier.sdk;
import android.util.Log;
-import java.lang.Comparable;
-import java.lang.Override;
-import java.lang.String;
-import java.util.ArrayList;
+import com.zerotier.sdk.util.StringUtils;
+
import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
-public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConfig> {
+/**
+ * Virtual network configuration
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkConfig
+ */
+public class VirtualNetworkConfig implements Comparable<VirtualNetworkConfig> {
+
private final static String TAG = "VirtualNetworkConfig";
public static final int MAX_MULTICAST_SUBSCRIPTIONS = 4096;
public static final int ZT_MAX_ZT_ASSIGNED_ADDRESSES = 16;
- private long nwid;
- private long mac;
- private String name;
- private VirtualNetworkStatus status;
- private VirtualNetworkType type;
- private int mtu;
- private boolean dhcp;
- private boolean bridge;
- private boolean broadcastEnabled;
- private int portError;
- private boolean enabled;
- private long netconfRevision;
- private InetSocketAddress[] assignedAddresses;
- private VirtualNetworkRoute[] routes;
- private VirtualNetworkDNS dns;
-
- private VirtualNetworkConfig() {
+ private final long nwid;
- }
+ private final long mac;
- public boolean equals(VirtualNetworkConfig cfg) {
- ArrayList<String> aaCurrent = new ArrayList<>();
- ArrayList<String> aaNew = new ArrayList<>();
- for (InetSocketAddress s : assignedAddresses) {
- aaCurrent.add(s.toString());
- }
- for (InetSocketAddress s : cfg.assignedAddresses) {
- aaNew.add(s.toString());
- }
- Collections.sort(aaCurrent);
- Collections.sort(aaNew);
- boolean aaEqual = aaCurrent.equals(aaNew);
-
- ArrayList<String> rCurrent = new ArrayList<>();
- ArrayList<String> rNew = new ArrayList<>();
- for (VirtualNetworkRoute r : routes) {
- rCurrent.add(r.toString());
+ private final String name;
+
+ private final VirtualNetworkStatus status;
+
+ private final VirtualNetworkType type;
+
+ private final int mtu;
+
+ private final boolean dhcp;
+
+ private final boolean bridge;
+
+ private final boolean broadcastEnabled;
+
+ //
+ // ANDROID-56: temporarily remove parameters to prevent crashing
+ //
+// private final int portError;
+//
+// private final long netconfRevision;
+
+ private final InetSocketAddress[] assignedAddresses;
+
+ private final VirtualNetworkRoute[] routes;
+
+ private final VirtualNetworkDNS dns;
+
+ public VirtualNetworkConfig(long nwid, long mac, String name, VirtualNetworkStatus status, VirtualNetworkType type, int mtu, boolean dhcp, boolean bridge, boolean broadcastEnabled, InetSocketAddress[] assignedAddresses, VirtualNetworkRoute[] routes, VirtualNetworkDNS dns) {
+ this.nwid = nwid;
+ this.mac = mac;
+ this.name = name;
+ this.status = status;
+ this.type = type;
+ if (mtu < 0) {
+ throw new RuntimeException("mtu < 0: " + mtu);
}
- for (VirtualNetworkRoute r : cfg.routes) {
- rNew.add(r.toString());
+ this.mtu = mtu;
+ this.dhcp = dhcp;
+ this.bridge = bridge;
+ this.broadcastEnabled = broadcastEnabled;
+// this.portError = portError;
+// if (netconfRevision < 0) {
+// throw new RuntimeException("netconfRevision < 0: " + netconfRevision);
+// }
+// this.netconfRevision = netconfRevision;
+ this.assignedAddresses = assignedAddresses;
+ this.routes = routes;
+ this.dns = dns;
+ }
+
+ @Override
+ public String toString() {
+ return "VirtualNetworkConfig(" + StringUtils.networkIdToString(nwid) + ", " + StringUtils.macAddressToString(mac) + ", " + name + ", " + status + ", " + type + ", " + mtu + ", " + dhcp + ", " + bridge + ", " + broadcastEnabled + ", " + Arrays.toString(assignedAddresses) + ", " + Arrays.toString(routes) + ", " + dns + ")";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+
+ if (!(o instanceof VirtualNetworkConfig)) {
+ return false;
}
- Collections.sort(rCurrent);
- Collections.sort(rNew);
- boolean routesEqual = rCurrent.equals(rNew);
+
+ VirtualNetworkConfig cfg = (VirtualNetworkConfig) o;
if (this.nwid != cfg.nwid) {
- Log.i(TAG, "nwid Changed. Old: " + Long.toHexString(this.nwid) + " (" + Long.toString(this.nwid) + "), " +
- "New: " + Long.toHexString(cfg.nwid) + " (" + Long.toString(cfg.nwid) + ")");
+ Log.i(TAG, "NetworkID Changed. Old: " + StringUtils.networkIdToString(this.nwid) + " (" + this.nwid + "), " +
+ "New: " + StringUtils.networkIdToString(cfg.nwid) + " (" + cfg.nwid + ")");
+
+ return false;
}
+
if (this.mac != cfg.mac) {
- Log.i(TAG, "MAC Changed. Old: " + Long.toHexString(this.mac) + ", New: " + Long.toHexString(cfg.mac));
+ Log.i(TAG, "MAC Changed. Old: " + StringUtils.macAddressToString(this.mac) + ", New: " + StringUtils.macAddressToString(cfg.mac));
+
+ return false;
}
if (!this.name.equals(cfg.name)) {
- Log.i(TAG, "Name Changed. Old: " + this.name + " New: "+ cfg.name);
+ Log.i(TAG, "Name Changed. Old: " + this.name + ", New: " + cfg.name);
+
+ return false;
}
- if (!this.type.equals(cfg.type)) {
- Log.i(TAG, "TYPE changed. Old " + this.type + ", New: " + cfg.type);
+ if (this.status != cfg.status) {
+ Log.i(TAG, "Status Changed. Old: " + this.status + ", New: " + cfg.status);
+
+ return false;
+ }
+
+ if (this.type != cfg.type) {
+ Log.i(TAG, "Type changed. Old " + this.type + ", New: " + cfg.type);
+
+ return false;
}
if (this.mtu != cfg.mtu) {
- Log.i(TAG, "MTU Changed. Old: " + this.mtu + ", New: " + cfg.mtu);
+ Log.i(TAG, "MTU Changed. Old: " + this.mtu + ", New: " + cfg.mtu);
+
+ return false;
}
if (this.dhcp != cfg.dhcp) {
Log.i(TAG, "DHCP Flag Changed. Old: " + this.dhcp + ", New: " + cfg.dhcp);
+
+ return false;
}
if (this.bridge != cfg.bridge) {
Log.i(TAG, "Bridge Flag Changed. Old: " + this.bridge + ", New: " + cfg.bridge);
+
+ return false;
}
if (this.broadcastEnabled != cfg.broadcastEnabled) {
- Log.i(TAG, "Broadcast Flag Changed. Old: "+ this.broadcastEnabled +", New: " + this.broadcastEnabled);
- }
+ Log.i(TAG, "Broadcast Flag Changed. Old: "+ this.broadcastEnabled + ", New: " + cfg.broadcastEnabled);
- if (this.portError != cfg.portError) {
- Log.i(TAG, "Port Error Changed. Old: " + this.portError + ", New: " + this.portError);
+ return false;
}
- if (this.enabled != cfg.enabled) {
- Log.i(TAG, "Enabled Changed. Old: " + this.enabled + ", New: " + this.enabled);
- }
+// if (this.portError != cfg.portError) {
+// Log.i(TAG, "Port Error Changed. Old: " + this.portError + ", New: " + cfg.portError);
+//
+// return false;
+// }
+//
+// if (this.netconfRevision != cfg.netconfRevision) {
+// Log.i(TAG, "NetConfRevision Changed. Old: " + this.netconfRevision + ", New: " + cfg.netconfRevision);
+//
+// return false;
+// }
+
+ if (!Arrays.equals(assignedAddresses, cfg.assignedAddresses)) {
+
+ ArrayList<String> aaCurrent = new ArrayList<>();
+ ArrayList<String> aaNew = new ArrayList<>();
+ for (InetSocketAddress s : assignedAddresses) {
+ aaCurrent.add(s.toString());
+ }
+ for (InetSocketAddress s : cfg.assignedAddresses) {
+ aaNew.add(s.toString());
+ }
+ Collections.sort(aaCurrent);
+ Collections.sort(aaNew);
- if (!aaEqual) {
Log.i(TAG, "Assigned Addresses Changed");
Log.i(TAG, "Old:");
for (String s : aaCurrent) {
Log.i(TAG, " " + s);
}
+ Log.i(TAG, "");
Log.i(TAG, "New:");
for (String s : aaNew) {
Log.i(TAG, " " +s);
}
+ Log.i(TAG, "");
+
+ return false;
}
- if (!routesEqual) {
+ if (!Arrays.equals(routes, cfg.routes)) {
+
+ ArrayList<String> rCurrent = new ArrayList<>();
+ ArrayList<String> rNew = new ArrayList<>();
+ for (VirtualNetworkRoute r : routes) {
+ rCurrent.add(r.toString());
+ }
+ for (VirtualNetworkRoute r : cfg.routes) {
+ rNew.add(r.toString());
+ }
+ Collections.sort(rCurrent);
+ Collections.sort(rNew);
+
Log.i(TAG, "Managed Routes Changed");
Log.i(TAG, "Old:");
for (String s : rCurrent) {
Log.i(TAG, " " + s);
}
+ Log.i(TAG, "");
Log.i(TAG, "New:");
for (String s : rNew) {
Log.i(TAG, " " + s);
}
+ Log.i(TAG, "");
+
+ return false;
}
- boolean dnsEquals = false;
- if (this.dns == null || cfg.dns == null) {
- dnsEquals = true;
- } else if (this.dns != null) {
- dnsEquals = this.dns.equals(cfg.dns);
+ boolean dnsEquals;
+ if (this.dns == null) {
+ //noinspection RedundantIfStatement
+ if (cfg.dns == null) {
+ dnsEquals = true;
+ } else {
+ dnsEquals = false;
+ }
+ } else {
+ if (cfg.dns == null) {
+ dnsEquals = false;
+ } else {
+ dnsEquals = this.dns.equals(cfg.dns);
+ }
+ }
+
+ if (!dnsEquals) {
+ return false;
}
- return this.nwid == cfg.nwid &&
- this.mac == cfg.mac &&
- this.name.equals(cfg.name) &&
- this.status.equals(cfg.status) &&
- this.type.equals(cfg.type) &&
- this.mtu == cfg.mtu &&
- this.dhcp == cfg.dhcp &&
- this.bridge == cfg.bridge &&
- this.broadcastEnabled == cfg.broadcastEnabled &&
- this.portError == cfg.portError &&
- this.enabled == cfg.enabled &&
- dnsEquals &&
- aaEqual && routesEqual;
+ return true;
}
+ @Override
public int compareTo(VirtualNetworkConfig cfg) {
- if(cfg.nwid == this.nwid) {
- return 0;
- } else {
- return this.nwid > cfg.nwid ? 1 : -1;
- }
+ return Long.compare(this.nwid, cfg.nwid);
+ }
+
+ @Override
+ public int hashCode() {
+
+ int result = 17;
+ result = 37 * result + (int) (nwid ^ (nwid >>> 32));
+ result = 37 * result + (int) (mac ^ (mac >>> 32));
+ result = 37 * result + name.hashCode();
+ result = 37 * result + status.hashCode();
+ result = 37 * result + type.hashCode();
+ result = 37 * result + mtu;
+ result = 37 * result + (dhcp ? 1 : 0);
+ result = 37 * result + (bridge ? 1 : 0);
+ result = 37 * result + (broadcastEnabled ? 1 : 0);
+// result = 37 * result + portError;
+// result = 37 * result + (int) (netconfRevision ^ (netconfRevision >>> 32));
+ result = 37 * result + Arrays.hashCode(assignedAddresses);
+ result = 37 * result + Arrays.hashCode(routes);
+ result = 37 * result + (dns == null ? 0 : dns.hashCode());
+
+ return result;
}
/**
* 64-bit ZeroTier network ID
*/
- public final long networkId() {
+ public long getNwid() {
return nwid;
}
/**
- * Ethernet MAC (40 bits) that should be assigned to port
+ * Ethernet MAC (48 bits) that should be assigned to port
*/
- public final long macAddress() {
+ public long getMac() {
return mac;
}
/**
* Network name (from network configuration master)
*/
- public final String name() {
+ public String getName() {
return name;
}
/**
* Network configuration request status
*/
- public final VirtualNetworkStatus networkStatus() {
+ public VirtualNetworkStatus getStatus() {
return status;
}
/**
* Network type
*/
- public final VirtualNetworkType networkType() {
+ public VirtualNetworkType getType() {
return type;
}
/**
* Maximum interface MTU
*/
- public final int mtu() {
+ public int getMtu() {
return mtu;
}
@@ -230,7 +338,7 @@ public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConf
* for security or other reasons. This is simply a netconf parameter that
* means 'DHCP is available on this network.'</p>
*/
- public final boolean isDhcpAvailable() {
+ public boolean isDhcp() {
return dhcp;
}
@@ -240,35 +348,35 @@ public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConf
* <p>This is informational. If this is false, bridged packets will simply
* be dropped and bridging won't work.</p>
*/
- public final boolean isBridgeEnabled() {
+ public boolean isBridge() {
return bridge;
}
/**
* If true, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic
*/
- public final boolean broadcastEnabled() {
+ public boolean isBroadcastEnabled() {
return broadcastEnabled;
}
/**
* If the network is in PORT_ERROR state, this is the error most recently returned by the port config callback
*/
- public final int portError() {
- return portError;
- }
+// public int getPortError() {
+// return portError;
+// }
/**
* Network config revision as reported by netconf master
*
* <p>If this is zero, it means we're still waiting for our netconf.</p>
*/
- public final long netconfRevision() {
- return netconfRevision;
- }
+// public long getNetconfRevision() {
+// return netconfRevision;
+// }
/**
- * ZeroTier-assigned addresses (in {@link java.net.InetSocketAddress} objects)
+ * ZeroTier-assigned addresses (in {@link InetSocketAddress} objects)
*
* For IP, the port number of the sockaddr_XX structure contains the number
* of bits in the address netmask. Only the IP address and port are used.
@@ -277,16 +385,21 @@ public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConf
* This is only used for ZeroTier-managed address assignments sent by the
* virtual network's configuration master.
*/
- public final InetSocketAddress[] assignedAddresses() {
+ public InetSocketAddress[] getAssignedAddresses() {
return assignedAddresses;
}
/**
- * ZeroTier-assigned routes (in {@link com.zerotier.sdk.VirtualNetworkRoute} objects)
- *
- * @return
+ * ZeroTier-assigned routes (in {@link VirtualNetworkRoute} objects)
*/
- public final VirtualNetworkRoute[] routes() { return routes; }
+ public VirtualNetworkRoute[] getRoutes() {
+ return routes;
+ }
- public final VirtualNetworkDNS dns() { return dns; }
+ /**
+ * Network specific DNS configuration
+ */
+ public VirtualNetworkDNS getDns() {
+ return dns;
+ }
}
diff --git a/java/src/com/zerotier/sdk/VirtualNetworkConfigListener.java b/java/src/com/zerotier/sdk/VirtualNetworkConfigListener.java
index 15ae301c..ce91e79d 100644
--- a/java/src/com/zerotier/sdk/VirtualNetworkConfigListener.java
+++ b/java/src/com/zerotier/sdk/VirtualNetworkConfigListener.java
@@ -25,11 +25,11 @@
* LLC. Start here: http://www.zerotier.com/
*/
-
package com.zerotier.sdk;
public interface VirtualNetworkConfigListener {
+
/**
* Callback called to update virtual network port configuration
*
@@ -40,7 +40,7 @@ public interface VirtualNetworkConfigListener {
* This in turn should be used by the underlying implementation to create
* and configure tap devices at the OS (or virtual network stack) layer.</P>
*
- * This should not call {@link Node#multicastSubscribe} or other network-modifying
+ * This should not call {@link Node#multicastSubscribe(long, long)} or other network-modifying
* methods, as this could cause a deadlock in multithreaded or interrupt
* driven environments.
*
@@ -53,8 +53,8 @@ public interface VirtualNetworkConfigListener {
* @param config {@link VirtualNetworkConfig} object with the new configuration
* @return 0 on success
*/
- public int onNetworkConfigurationUpdated(
+ int onNetworkConfigurationUpdated(
long nwid,
VirtualNetworkConfigOperation op,
VirtualNetworkConfig config);
-} \ No newline at end of file
+}
diff --git a/java/src/com/zerotier/sdk/VirtualNetworkConfigOperation.java b/java/src/com/zerotier/sdk/VirtualNetworkConfigOperation.java
index b70eb478..a1981bd1 100644
--- a/java/src/com/zerotier/sdk/VirtualNetworkConfigOperation.java
+++ b/java/src/com/zerotier/sdk/VirtualNetworkConfigOperation.java
@@ -24,26 +24,55 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
+/**
+ * Virtual network configuration update type
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkConfigOperation
+ */
public enum VirtualNetworkConfigOperation {
+
/**
* Network is coming up (either for the first time or after service restart)
*/
- VIRTUAL_NETWORK_CONFIG_OPERATION_UP,
+ VIRTUAL_NETWORK_CONFIG_OPERATION_UP(1),
/**
* Network configuration has been updated
*/
- VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE,
+ VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE(2),
/**
* Network is going down (not permanently)
*/
- VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,
+ VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN(3),
/**
* Network is going down permanently (leave/delete)
*/
- VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY
+ VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY(4);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ VirtualNetworkConfigOperation(int id) {
+ this.id = id;
+ }
+
+ public static VirtualNetworkConfigOperation fromInt(int id) {
+ switch (id) {
+ case 1:
+ return VIRTUAL_NETWORK_CONFIG_OPERATION_UP;
+ case 2:
+ return VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE;
+ case 3:
+ return VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN;
+ case 4:
+ return VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
}
diff --git a/java/src/com/zerotier/sdk/VirtualNetworkDNS.java b/java/src/com/zerotier/sdk/VirtualNetworkDNS.java
index 7046fd42..6e4bb3d2 100644
--- a/java/src/com/zerotier/sdk/VirtualNetworkDNS.java
+++ b/java/src/com/zerotier/sdk/VirtualNetworkDNS.java
@@ -8,15 +8,48 @@ package com.zerotier.sdk;
import java.net.InetSocketAddress;
import java.util.ArrayList;
+/**
+ * DNS configuration to be pushed on a virtual network
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkDNS
+ */
public class VirtualNetworkDNS implements Comparable<VirtualNetworkDNS> {
- private String domain;
- private ArrayList<InetSocketAddress> servers;
- public VirtualNetworkDNS() {}
+ private final String domain;
+ private final ArrayList<InetSocketAddress> servers;
+
+ public VirtualNetworkDNS(String domain, ArrayList<InetSocketAddress> servers) {
+ this.domain = domain;
+ this.servers = servers;
+ }
+
+ @Override
+ public String toString() {
+ return "VirtualNetworkDNS(" + domain + ", " + servers + ")";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+
+ if (o == null) {
+ return false;
+ }
+
+ if (!(o instanceof VirtualNetworkDNS)) {
+ return false;
+ }
- public boolean equals(VirtualNetworkDNS o) {
- if (o == null) return false;
- return domain.equals(o.domain) && servers.equals(o.servers);
+ VirtualNetworkDNS d = (VirtualNetworkDNS) o;
+
+ if (!domain.equals(d.domain)) {
+ return false;
+ }
+
+ if (!servers.equals(d.servers)) {
+ return false;
+ }
+
+ return true;
}
@Override
@@ -24,7 +57,21 @@ public class VirtualNetworkDNS implements Comparable<VirtualNetworkDNS> {
return domain.compareTo(o.domain);
}
- public String getSearchDomain() { return domain; }
+ @Override
+ public int hashCode() {
+
+ int result = 17;
+ result = 37 * result + domain.hashCode();
+ result = 37 * result + servers.hashCode();
+
+ return result;
+ }
+
+ public String getDomain() {
+ return domain;
+ }
- public ArrayList<InetSocketAddress> getServers() { return servers; }
+ public ArrayList<InetSocketAddress> getServers() {
+ return servers;
+ }
}
diff --git a/java/src/com/zerotier/sdk/VirtualNetworkFrameListener.java b/java/src/com/zerotier/sdk/VirtualNetworkFrameListener.java
index 9ad32282..650c9ced 100644
--- a/java/src/com/zerotier/sdk/VirtualNetworkFrameListener.java
+++ b/java/src/com/zerotier/sdk/VirtualNetworkFrameListener.java
@@ -28,17 +28,18 @@
package com.zerotier.sdk;
public interface VirtualNetworkFrameListener {
+
/**
* Function to send a frame out to a virtual network port
*
* @param nwid ZeroTier One network ID
* @param srcMac source MAC address
* @param destMac destination MAC address
- * @param ethertype
- * @param vlanId
+ * @param etherType EtherType
+ * @param vlanId VLAN ID
* @param frameData data to send
*/
- public void onVirtualNetworkFrame(
+ void onVirtualNetworkFrame(
long nwid,
long srcMac,
long destMac,
diff --git a/java/src/com/zerotier/sdk/VirtualNetworkRoute.java b/java/src/com/zerotier/sdk/VirtualNetworkRoute.java
index 8dd700c0..afd9ee45 100644
--- a/java/src/com/zerotier/sdk/VirtualNetworkRoute.java
+++ b/java/src/com/zerotier/sdk/VirtualNetworkRoute.java
@@ -29,80 +29,135 @@ package com.zerotier.sdk;
import java.net.InetSocketAddress;
-public final class VirtualNetworkRoute implements Comparable<VirtualNetworkRoute>
+/**
+ * A route to be pushed on a virtual network
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkRoute
+ */
+public class VirtualNetworkRoute implements Comparable<VirtualNetworkRoute>
{
- private VirtualNetworkRoute() {
- target = null;
- via = null;
- flags = 0;
- metric = 0;
- }
-
/**
* Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default
*/
- public InetSocketAddress target;
-
+ private final InetSocketAddress target;
+
/**
* Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway)
*/
- public InetSocketAddress via;
+ private final InetSocketAddress via;
/**
* Route flags
*/
- public int flags;
+ private final int flags;
/**
* Route metric (not currently used)
*/
- public int metric;
+ private final int metric;
- @Override
+ public VirtualNetworkRoute(InetSocketAddress target, InetSocketAddress via, int flags, int metric) {
+ this.target = target;
+ this.via = via;
+ this.flags = flags;
+ this.metric = metric;
+ }
+
+ @Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(target.toString());
- if (via != null) {
- sb.append(via.toString());
- }
- return sb.toString();
+ return "VirtualNetworkRoute(" + target + ", " + via + ", " + flags + ", " + metric + ")";
}
@Override
- public int compareTo(VirtualNetworkRoute other) {
- return this.toString().compareTo(other.toString());
- }
-
- public boolean equals(VirtualNetworkRoute other) {
- boolean targetEquals = false;
- if (target == null && other.target == null) {
- targetEquals = true;
- }
- else if (target == null && other.target != null) {
- targetEquals = false;
- }
- else if (target != null && other.target == null) {
- targetEquals = false;
+ public int compareTo(VirtualNetworkRoute other) {
+ throw new RuntimeException("Unimplemented");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+
+ if (!(o instanceof VirtualNetworkRoute)) {
+ return false;
}
- else {
- targetEquals = target.toString().equals(other.target.toString());
+
+ VirtualNetworkRoute other = (VirtualNetworkRoute) o;
+
+ boolean targetEquals;
+ if (target == null) {
+ //noinspection RedundantIfStatement
+ if (other.target == null) {
+ targetEquals = true;
+ } else {
+ targetEquals = false;
+ }
+ } else {
+ if (other.target == null) {
+ targetEquals = false;
+ } else {
+ targetEquals = target.equals(other.target);
+ }
}
+ if (!targetEquals) {
+ return false;
+ }
boolean viaEquals;
- if (via == null && other.via == null) {
- viaEquals = true;
+ if (via == null) {
+ //noinspection RedundantIfStatement
+ if (other.via == null) {
+ viaEquals = true;
+ } else {
+ viaEquals = false;
+ }
+ } else {
+ if (other.via == null) {
+ viaEquals = false;
+ } else {
+ viaEquals = via.equals(other.via);
+ }
}
- else if (via == null && other.via != null) {
- viaEquals = false;
+
+ if (!viaEquals) {
+ return false;
}
- else if (via != null && other.via == null) {
- viaEquals = false;
+
+ if (flags != other.flags) {
+ return false;
}
- else {
- viaEquals = via.toString().equals(other.via.toString());
+
+ if (metric != other.metric) {
+ return false;
}
- return viaEquals && targetEquals;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+
+ int result = 17;
+ result = 37 * result + (target == null ? 0 : target.hashCode());
+ result = 37 * result + (via == null ? 0 : via.hashCode());
+ result = 37 * result + flags;
+ result = 37 * result + metric;
+
+ return result;
+ }
+
+ public InetSocketAddress getTarget() {
+ return target;
+ }
+
+ public InetSocketAddress getVia() {
+ return via;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public int getMetric() {
+ return metric;
}
}
diff --git a/java/src/com/zerotier/sdk/VirtualNetworkStatus.java b/java/src/com/zerotier/sdk/VirtualNetworkStatus.java
index 68e01bd6..8a32ba6a 100644
--- a/java/src/com/zerotier/sdk/VirtualNetworkStatus.java
+++ b/java/src/com/zerotier/sdk/VirtualNetworkStatus.java
@@ -24,41 +24,76 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
+/**
+ * Virtual network status codes
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkStatus
+ */
public enum VirtualNetworkStatus {
+
/**
* Waiting for network configuration (also means revision == 0)
*/
- NETWORK_STATUS_REQUESTING_CONFIGURATION,
+ NETWORK_STATUS_REQUESTING_CONFIGURATION(0),
/**
* Configuration received and we are authorized
*/
- NETWORK_STATUS_OK,
-
- /**
- * Netconf master said SSO auth required.
- */
- NETWORK_STATUS_AUTHENTICATION_REQUIRED,
+ NETWORK_STATUS_OK(1),
/**
* Netconf master told us 'nope'
*/
- NETWORK_STATUS_ACCESS_DENIED,
+ NETWORK_STATUS_ACCESS_DENIED(2),
/**
* Netconf master exists, but this virtual network does not
*/
- NETWORK_STATUS_NOT_FOUND,
+ NETWORK_STATUS_NOT_FOUND(3),
/**
* Initialization of network failed or other internal error
*/
- NETWORK_STATUS_PORT_ERROR,
+ NETWORK_STATUS_PORT_ERROR(4),
/**
* ZeroTier One version too old
*/
- NETWORK_STATUS_CLIENT_TOO_OLD
+ NETWORK_STATUS_CLIENT_TOO_OLD(5),
+
+ /**
+ * External authentication is required (e.g. SSO)
+ */
+ NETWORK_STATUS_AUTHENTICATION_REQUIRED(6);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ VirtualNetworkStatus(int id) {
+ this.id = id;
+ }
+
+ public static VirtualNetworkStatus fromInt(int id) {
+ switch (id) {
+ case 0:
+ return NETWORK_STATUS_REQUESTING_CONFIGURATION;
+ case 1:
+ return NETWORK_STATUS_OK;
+ case 2:
+ return NETWORK_STATUS_ACCESS_DENIED;
+ case 3:
+ return NETWORK_STATUS_NOT_FOUND;
+ case 4:
+ return NETWORK_STATUS_PORT_ERROR;
+ case 5:
+ return NETWORK_STATUS_CLIENT_TOO_OLD;
+ case 6:
+ return NETWORK_STATUS_AUTHENTICATION_REQUIRED;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
}
diff --git a/java/src/com/zerotier/sdk/VirtualNetworkType.java b/java/src/com/zerotier/sdk/VirtualNetworkType.java
index ab1f4e08..44be8864 100644
--- a/java/src/com/zerotier/sdk/VirtualNetworkType.java
+++ b/java/src/com/zerotier/sdk/VirtualNetworkType.java
@@ -24,16 +24,41 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
+/**
+ * Virtual network type codes
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkType
+ */
public enum VirtualNetworkType {
+
/**
* Private networks are authorized via certificates of membership
*/
- NETWORK_TYPE_PRIVATE,
+ NETWORK_TYPE_PRIVATE(0),
/**
* Public networks have no access control -- they'll always be AUTHORIZED
*/
- NETWORK_TYPE_PUBLIC
+ NETWORK_TYPE_PUBLIC(1);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ VirtualNetworkType(int id) {
+ this.id = id;
+ }
+
+ public static VirtualNetworkType fromInt(int id) {
+ switch (id) {
+ case 0:
+ return NETWORK_TYPE_PRIVATE;
+ case 1:
+ return NETWORK_TYPE_PUBLIC;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
}
diff --git a/java/src/com/zerotier/sdk/util/StringUtils.java b/java/src/com/zerotier/sdk/util/StringUtils.java
new file mode 100644
index 00000000..c7bcc5d9
--- /dev/null
+++ b/java/src/com/zerotier/sdk/util/StringUtils.java
@@ -0,0 +1,52 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2023 ZeroTier, Inc. https://www.zerotier.com/
+ */
+
+package com.zerotier.sdk.util;
+
+public class StringUtils {
+
+ /**
+ * Convert mac address to string.
+ *
+ * @param mac MAC address
+ * @return string in XX:XX:XX:XX:XX:XX format
+ */
+ public static String macAddressToString(long mac) {
+
+ int[] macChars = new int[6];
+ for (int i = 0; i < 6; i++) {
+ macChars[i] = (int) (mac % 256);
+ mac >>= 8;
+ }
+
+ return String.format("%02x:%02x:%02x:%02x:%02x:%02x", macChars[5], macChars[4], macChars[3], macChars[2], macChars[1], macChars[0]);
+ }
+
+ /**
+ * Convert long to hex string.
+ *
+ * @param networkId long
+ * @return string with 0 padding
+ */
+ public static String networkIdToString(long networkId) {
+ return String.format("%016x", networkId);
+ }
+
+ /**
+ * Convert node address to string.
+ *
+ * Node addresses are 40 bits, so print 10 hex characters.
+ *
+ * @param address Node address
+ * @return formatted string
+ */
+ public static String addressToString(long address) {
+ return String.format("%010x", address);
+ }
+
+ public static String etherTypeToString(long etherType) {
+ return String.format("%04x", etherType);
+ }
+}
diff --git a/java/test/com/zerotier/sdk/util/StringUtilsTest.java b/java/test/com/zerotier/sdk/util/StringUtilsTest.java
new file mode 100644
index 00000000..257b14a9
--- /dev/null
+++ b/java/test/com/zerotier/sdk/util/StringUtilsTest.java
@@ -0,0 +1,73 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2023 ZeroTier, Inc. https://www.zerotier.com/
+ */
+
+package com.zerotier.sdk.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class StringUtilsTest {
+
+ public StringUtilsTest() {
+ }
+
+ public String oldMacDisplay(long mac) {
+
+ String macStr = Long.toHexString(mac);
+
+ if (macStr.length() > 12) {
+ throw new RuntimeException();
+ }
+
+ while (macStr.length() < 12) {
+ //noinspection StringConcatenationInLoop
+ macStr = "0" + macStr;
+ }
+
+ //noinspection StringBufferReplaceableByString
+ StringBuilder displayMac = new StringBuilder();
+ displayMac.append(macStr.charAt(0));
+ displayMac.append(macStr.charAt(1));
+ displayMac.append(':');
+ displayMac.append(macStr.charAt(2));
+ displayMac.append(macStr.charAt(3));
+ displayMac.append(':');
+ displayMac.append(macStr.charAt(4));
+ displayMac.append(macStr.charAt(5));
+ displayMac.append(':');
+ displayMac.append(macStr.charAt(6));
+ displayMac.append(macStr.charAt(7));
+ displayMac.append(':');
+ displayMac.append(macStr.charAt(8));
+ displayMac.append(macStr.charAt(9));
+ displayMac.append(':');
+ displayMac.append(macStr.charAt(10));
+ displayMac.append(macStr.charAt(11));
+
+ return displayMac.toString();
+ }
+
+ @Test
+ public void testMacDisplay() {
+
+ long mac1 = 1234567891;
+ assertThat(StringUtils.macAddressToString(mac1)).isEqualTo(oldMacDisplay(mac1));
+
+ long mac2 = 999999999;
+ assertThat(StringUtils.macAddressToString(mac2)).isEqualTo(oldMacDisplay(mac2));
+
+ long mac3 = 0x7fffffffffffL;
+ assertThat(StringUtils.macAddressToString(mac3)).isEqualTo(oldMacDisplay(mac3));
+ assertThat(StringUtils.macAddressToString(mac3)).isEqualTo("7f:ff:ff:ff:ff:ff");
+
+ long mac4 = 0x7fafcf3f8fffL;
+ assertThat(StringUtils.macAddressToString(mac4)).isEqualTo(oldMacDisplay(mac4));
+ assertThat(StringUtils.macAddressToString(mac4)).isEqualTo("7f:af:cf:3f:8f:ff");
+ }
+}