Merge branch 'dev' into tl-macos-multiple-addresses

This commit is contained in:
Grant Limberg 2023-03-06 09:33:06 -08:00 committed by GitHub
commit bf8b6e4a7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 2345 additions and 2430 deletions

View file

@ -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;
}

View file

@ -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

236
java/jni/ZT_jnicache.cpp Normal file
View file

@ -0,0 +1,236 @@
//
// 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"));
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(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);
}

92
java/jni/ZT_jnicache.h Normal file
View file

@ -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

View file

@ -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;
}

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -15,18 +15,15 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef ZT_jniutils_h_ #ifndef ZT_jniutils_h_
#define ZT_jniutils_h_ #define ZT_jniutils_h_
#include <stdio.h>
#include <jni.h> #include <jni.h>
#include <ZeroTierOne.h> #include <ZeroTierOne.h>
#ifdef __cplusplus #include <limits> // for numeric_limits
extern "C" { #include <sys/socket.h> // for sockaddr_storage
#endif
#define LOG_TAG "ZeroTierOneJNI"
#if defined(__ANDROID__) #if defined(__ANDROID__)
@ -55,6 +52,34 @@ extern "C" {
#define LOGE(...) fprintf(stdout, __VA_ARGS__) #define LOGE(...) fprintf(stdout, __VA_ARGS__)
#endif #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 createResultObject(JNIEnv *env, ZT_ResultCode code);
jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status); jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status);
jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type); 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 newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr);
jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr); jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr);
int addressPort(const sockaddr_storage addr);
jobject newMulticastGroup(JNIEnv *env, const ZT_MulticastGroup &mc);
jobject newPeer(JNIEnv *env, const ZT_Peer &peer); jobject newPeer(JNIEnv *env, const ZT_Peer &peer);
jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp); 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); jobject newVirtualNetworkDNS(JNIEnv *env, const ZT_VirtualNetworkDNS &dns);
#ifdef __cplusplus jobject newNodeStatus(JNIEnv *env, const ZT_NodeStatus &status);
}
#endif
#endif 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;
}
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_

File diff suppressed because it is too large Load diff

View file

@ -10,9 +10,17 @@ extern "C" {
/* /*
* Class: com_zerotier_sdk_Node * Class: com_zerotier_sdk_Node
* Method: node_init * 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 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); (JNIEnv *, jobject, jlong);
/* /*
@ -34,7 +42,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame
/* /*
* Class: com_zerotier_sdk_Node * Class: com_zerotier_sdk_Node
* Method: processWirePacket * 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 JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket
(JNIEnv *, jobject, jlong, jlong, jlong, jobject, jbyteArray, jlongArray); (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 * Class: com_zerotier_sdk_Node
* Method: networks * Method: networkConfigs
* Signature: (J)[Lcom/zerotier/sdk/VirtualNetworkConfig; * 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); (JNIEnv *, jobject, jlong);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -24,6 +24,7 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks * redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/ * LLC. Start here: http://www.zerotier.com/
*/ */
package com.zerotier.sdk; package com.zerotier.sdk;
public interface DataStoreGetListener { public interface DataStoreGetListener {
@ -48,7 +49,7 @@ public interface DataStoreGetListener {
* @param out_buffer buffer to put the object in * @param out_buffer buffer to put the object in
* @return size of the object * @return size of the object
*/ */
public long onDataStoreGet( long onDataStoreGet(
String name, String name,
byte[] out_buffer); byte[] out_buffer);
} }

View file

@ -24,6 +24,7 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks * redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/ * LLC. Start here: http://www.zerotier.com/
*/ */
package com.zerotier.sdk; package com.zerotier.sdk;
public interface DataStorePutListener { public interface DataStorePutListener {
@ -43,7 +44,7 @@ public interface DataStorePutListener {
* @param secure set to user read/write only. * @param secure set to user read/write only.
* @return 0 on success. * @return 0 on success.
*/ */
public int onDataStorePut( int onDataStorePut(
String name, String name,
byte[] buffer, byte[] buffer,
boolean secure); boolean secure);
@ -54,6 +55,6 @@ public interface DataStorePutListener {
* @param name Object name * @param name Object name
* @return 0 on success. * @return 0 on success.
*/ */
public int onDelete( int onDelete(
String name); String name);
} }

View file

@ -27,26 +27,32 @@
package com.zerotier.sdk; package com.zerotier.sdk;
/**
* Status codes sent to status update callback when things happen
*
* Defined in ZeroTierOne.h as ZT_Event
*/
public enum Event { public enum Event {
/** /**
* Node has been initialized * Node has been initialized
* *
* This is the first event generated, and is always sent. It may occur * This is the first event generated, and is always sent. It may occur
* before Node's constructor returns. * before Node's constructor returns.
*/ */
EVENT_UP, EVENT_UP(0),
/** /**
* Node is offline -- network does not seem to be reachable by any available strategy * 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 * Node is online -- at least one upstream node appears reachable
* *
* Meta-data: none * Meta-data: none
*/ */
EVENT_ONLINE, EVENT_ONLINE(2),
/** /**
* Node is shutting down * Node is shutting down
@ -55,7 +61,7 @@ public enum Event {
* It's done for convenience, since cleaning up other state in the event * It's done for convenience, since cleaning up other state in the event
* handler may appear more idiomatic.</p> * handler may appear more idiomatic.</p>
*/ */
EVENT_DOWN, EVENT_DOWN(3),
/** /**
* Your identity has collided with another node's ZeroTier address * 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 * 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> * 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 * Trace (debugging) message
@ -94,5 +100,55 @@ public enum Event {
* *
* <p>Meta-data: {@link String}, TRACE message</p> * <p>Meta-data: {@link String}, TRACE message</p>
*/ */
EVENT_TRACE 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);
}
}
}

View file

@ -27,19 +27,17 @@
package com.zerotier.sdk; package com.zerotier.sdk;
import java.net.InetSocketAddress;
import java.lang.String;
/** /**
* Interface to handle callbacks for ZeroTier One events. * Interface to handle callbacks for ZeroTier One events.
*/ */
public interface EventListener { public interface EventListener {
/** /**
* Callback for events with no other associated metadata * Callback for events with no other associated metadata
* *
* @param event {@link Event} enum * @param event {@link Event} enum
*/ */
public void onEvent(Event event); void onEvent(Event event);
/** /**
* Trace messages * Trace messages
@ -48,5 +46,5 @@ public interface EventListener {
* *
* @param message the trace message * @param message the trace message
*/ */
public void onTrace(String message); void onTrace(String message);
} }

View file

@ -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 <adam@adamh.cz>, 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());
}
}

View file

@ -28,95 +28,72 @@
package com.zerotier.sdk; package com.zerotier.sdk;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.io.IOException;
/** /**
* A ZeroTier One node * A ZeroTier One node
*/ */
public class Node { public class Node {
static { static {
try { System.loadLibrary("ZeroTierOneJNI");
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();
}
}
}
private static final String TAG = "NODE"; private static final String TAG = "NODE";
/** /**
* Node ID for JNI purposes. * Node ID for JNI purposes.
* Currently set to the now value passed in at the constructor * Currently set to the now value passed in at the constructor
*
* -1 if the node has already been closed
*/ */
private long nodeId; private final 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;
/** /**
* Create a new ZeroTier One node * 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 * <p>Note that this can take a few seconds the first time it's called, as it
* will generate an identity.</p> * 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 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 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 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 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. * @param pathChecker User written instance of the {@link PathChecker} interface. Not required and can be null.
*/ */
public Node(long now, public ResultCode init(
DataStoreGetListener getListener, DataStoreGetListener getListener,
DataStorePutListener putListener, DataStorePutListener putListener,
PacketSender sender, PacketSender sender,
EventListener eventListener, EventListener eventListener,
VirtualNetworkFrameListener frameListener, VirtualNetworkFrameListener frameListener,
VirtualNetworkConfigListener configListener, VirtualNetworkConfigListener configListener,
PathChecker pathChecker) throws NodeException PathChecker pathChecker) throws NodeException {
{ ResultCode rc = node_init(
this.nodeId = now; nodeId,
getListener,
this.getListener = getListener; putListener,
this.putListener = putListener; sender,
this.sender = sender; eventListener,
this.eventListener = eventListener; frameListener,
this.frameListener = frameListener; configListener,
this.configListener = configListener; pathChecker);
this.pathChecker = pathChecker; if(rc != ResultCode.RESULT_OK) {
ResultCode rc = node_init(now);
if(rc != ResultCode.RESULT_OK)
{
// TODO: Throw Exception
throw new NodeException(rc.toString()); throw new NodeException(rc.toString());
} }
} return rc;
}
public boolean isInited() {
return node_isInited(nodeId);
}
/** /**
* Close this Node. * 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> * <p>The Node object can no longer be used once this method is called.</p>
*/ */
public void close() { public void close() {
if(nodeId != -1) { node_delete(nodeId);
node_delete(nodeId);
nodeId = -1;
}
} }
@Override @Override
protected void finalize() { public String toString() {
close(); return "Node(" + nodeId + ")";
} }
/** /**
@ -166,6 +140,7 @@ public class Node {
* Process a packet received from the physical wire * Process a packet received from the physical wire
* *
* @param now Current clock in milliseconds * @param now Current clock in milliseconds
* @param localSocket Local socket or -1
* @param remoteAddress Origin of packet * @param remoteAddress Origin of packet
* @param packetData Packet data * @param packetData Packet data
* @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() * @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 * @return List of networks or NULL on failure
*/ */
public VirtualNetworkConfig[] networks() { public VirtualNetworkConfig[] networkConfigs() {
return networks(nodeId); return networkConfigs(nodeId);
} }
/** /**
@ -408,7 +383,17 @@ public class Node {
// //
// function declarations for JNI // 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); private native void node_delete(long nodeId);
@ -471,5 +456,5 @@ public class Node {
private native Peer[] peers(long nodeId); private native Peer[] peers(long nodeId);
private native VirtualNetworkConfig[] networks(long nodeId); private native VirtualNetworkConfig[] networkConfigs(long nodeId);
} }

View file

@ -27,10 +27,11 @@
package com.zerotier.sdk; 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) { public NodeException(String message) {
super(message); super(message);
} }
} }

View file

@ -27,43 +27,64 @@
package com.zerotier.sdk; package com.zerotier.sdk;
public final class NodeStatus { import com.zerotier.sdk.util.StringUtils;
private long address;
private String publicIdentity;
private String secretIdentity;
private boolean online;
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 * 40-bit ZeroTier address of this node
*/ */
public final long getAddress() { public long getAddress() {
return address; return address;
} }
/** /**
* Public identity in string-serialized form (safe to send to others) * Public identity in string-serialized form (safe to send to others)
* *
* <p>This identity will remain valid as long as the node exists.</p> * <p>This identity will remain valid as long as the node exists.</p>
*/ */
public final String getPublicIdentity() { public String getPublicIdentity() {
return publicIdentity; return publicIdentity;
} }
/** /**
* Full identity including secret key in string-serialized form * Full identity including secret key in string-serialized form
* *
* <p>This identity will remain valid as long as the node exists.</p> * <p>This identity will remain valid as long as the node exists.</p>
*/ */
public final String getSecretIdentity() { public String getSecretIdentity() {
return secretIdentity; return secretIdentity;
} }
/** /**
* True if some kind of connectivity appears available * True if some kind of connectivity appears available
*/ */
public final boolean isOnline() { public boolean isOnline() {
return online; return online;
} }
} }

View file

@ -24,12 +24,14 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks * redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/ * LLC. Start here: http://www.zerotier.com/
*/ */
package com.zerotier.sdk; package com.zerotier.sdk;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
public interface PacketSender { public interface PacketSender {
/** /**
* Function to send a ZeroTier packet out over the wire * 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 localSocket socket file descriptor to send from. Set to -1 if not specified.
* @param remoteAddr {@link InetSocketAddress} to send to * @param remoteAddr {@link InetSocketAddress} to send to
* @param packetData data to send * @param packetData data to send
* @param ttl TTL is ignored
* @return 0 on success, any error code on failure. * @return 0 on success, any error code on failure.
*/ */
public int onSendPacketRequested( int onSendPacketRequested(
long localSocket, long localSocket,
InetSocketAddress remoteAddr, InetSocketAddress remoteAddr,
byte[] packetData, byte[] packetData,

View file

@ -8,6 +8,7 @@ package com.zerotier.sdk;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
public interface PathChecker { public interface PathChecker {
/** /**
* Callback to check whether a path should be used for ZeroTier traffic * 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 ztAddress ZeroTier address or 0 for none/any
* @param localSocket Local interface socket. -1 if unspecified * @param localSocket Local interface socket. -1 if unspecified
* @param remoteAddress remote address * @param remoteAddress remote address
* @return true if the path should be used
*/ */
boolean onPathCheck(long ztAddress, long localSocket, InetSocketAddress remoteAddress); boolean onPathCheck(long ztAddress, long localSocket, InetSocketAddress remoteAddress);

View file

@ -27,68 +27,92 @@
package com.zerotier.sdk; 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 { public class Peer {
private long address;
private int versionMajor;
private int versionMinor;
private int versionRev;
private int latency;
private PeerRole role;
private PeerPhysicalPath[] paths;
private Peer() {} private final long address;
private final int versionMajor;
private final int versionMinor;
private final int versionRev;
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) * ZeroTier address (40 bits)
*/ */
public final long address() { public long getAddress() {
return address; return address;
} }
/** /**
* Remote major version or -1 if not known * Remote major version or -1 if not known
*/ */
public final int versionMajor() { public int getVersionMajor() {
return versionMajor; return versionMajor;
} }
/** /**
* Remote minor version or -1 if not known * Remote minor version or -1 if not known
*/ */
public final int versionMinor() { public int getVersionMinor() {
return versionMinor; return versionMinor;
} }
/** /**
* Remote revision or -1 if not known * Remote revision or -1 if not known
*/ */
public final int versionRev() { public int getVersionRev() {
return versionRev; return versionRev;
} }
/** /**
* Last measured latency in milliseconds or zero if unknown * Last measured latency in milliseconds or zero if unknown
*/ */
public final int latency() { public int getLatency() {
return latency; return latency;
} }
/** /**
* What trust hierarchy role does this device have? * What trust hierarchy role does this device have?
*/ */
public final PeerRole role() { public PeerRole getRole() {
return role; return role;
} }
/** /**
* Known network paths to peer * Known network paths to peer
*/ */
public final PeerPhysicalPath[] paths() { public PeerPhysicalPath[] getPaths() {
return paths; return paths;
} }
} }

View file

@ -31,48 +31,62 @@ import java.net.InetSocketAddress;
/** /**
* Physical network path to a peer * Physical network path to a peer
*
* Defined in ZeroTierOne.h as ZT_PeerPhysicalPath
*/ */
public final class PeerPhysicalPath { public class PeerPhysicalPath {
private InetSocketAddress address;
private long lastSend;
private long lastReceive;
private boolean fixed;
private boolean preferred;
private 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;
}
@Override
public String toString() {
return "PeerPhysicalPath(" + address + ", " + lastSend + ", " + lastReceive + ", " + preferred + ")";
}
/** /**
* Address of endpoint * Address of endpoint
*/ */
public final InetSocketAddress address() { public InetSocketAddress getAddress() {
return address; return address;
} }
/** /**
* Time of last send in milliseconds or 0 for never * Time of last send in milliseconds or 0 for never
*/ */
public final long lastSend() { public long getLastSend() {
return lastSend; return lastSend;
} }
/** /**
* Time of last receive in milliseconds or 0 for never * Time of last receive in milliseconds or 0 for never
*/ */
public final long lastReceive() { public long getLastReceive() {
return lastReceive; return lastReceive;
} }
/**
* Is path fixed? (i.e. not learned, static)
*/
public final boolean isFixed() {
return fixed;
}
/** /**
* Is path preferred? * Is path preferred?
*/ */
public final boolean isPreferred() { public boolean isPreferred() {
return preferred; return preferred;
} }
} }

View file

@ -27,19 +27,45 @@
package com.zerotier.sdk; package com.zerotier.sdk;
/**
* What trust hierarchy role does this peer have?
*
* Defined in ZeroTierOne.h as ZT_PeerRole
*/
public enum PeerRole { public enum PeerRole {
/** /**
* An ordinary node * An ordinary node
*/ */
PEER_ROLE_LEAF, PEER_ROLE_LEAF(0),
/** /**
* moon root * moon root
*/ */
PEER_ROLE_MOON, PEER_ROLE_MOON(1),
/** /**
* planetary root * planetary root
*/ */
PEER_ROLE_PLANET 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);
}
}
}

View file

@ -34,12 +34,20 @@ package com.zerotier.sdk;
* occurs, the node should be considered to not be working correctly. These * occurs, the node should be considered to not be working correctly. These
* indicate serious problems like an inaccessible data store or a compile * indicate serious problems like an inaccessible data store or a compile
* problem.</p> * problem.</p>
*
* Defined in ZeroTierOne.h as ZT_ResultCode
*/ */
public enum ResultCode { public enum ResultCode {
/** /**
* Operation completed normally * 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) // Fatal errors (>=100, <1000)
/** /**
@ -68,12 +76,36 @@ public enum ResultCode {
RESULT_ERROR_BAD_PARAMETER(1002); RESULT_ERROR_BAD_PARAMETER(1002);
private final int id;
private final int id;
ResultCode(int id) { this.id = id; }
public int getValue() { return id; }
public boolean isFatal(int id) { ResultCode(int id) {
return (id > 100 && id < 1000); 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() {
return (id >= 100 && id < 1000);
}
}

View file

@ -27,10 +27,27 @@
package com.zerotier.sdk; package com.zerotier.sdk;
public final class Version { public class Version {
private Version() {}
private final int major;
public int major = 0; private final int minor;
public int minor = 0; private final int revision;
public int revision = 0;
} 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;
}
}

View file

@ -29,197 +29,302 @@ package com.zerotier.sdk;
import android.util.Log; import android.util.Log;
import java.lang.Comparable; import com.zerotier.sdk.util.StringUtils;
import java.lang.Override;
import java.lang.String;
import java.util.ArrayList;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; 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"; private final static String TAG = "VirtualNetworkConfig";
public static final int MAX_MULTICAST_SUBSCRIPTIONS = 4096; public static final int MAX_MULTICAST_SUBSCRIPTIONS = 4096;
public static final int ZT_MAX_ZT_ASSIGNED_ADDRESSES = 16; public static final int ZT_MAX_ZT_ASSIGNED_ADDRESSES = 16;
private long nwid; private final 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 mac;
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;
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, int portError, long netconfRevision, 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);
}
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;
} }
public boolean equals(VirtualNetworkConfig cfg) { @Override
ArrayList<String> aaCurrent = new ArrayList<>(); public String toString() {
ArrayList<String> aaNew = new ArrayList<>(); return "VirtualNetworkConfig(" + StringUtils.networkIdToString(nwid) + ", " + StringUtils.macAddressToString(mac) + ", " + name + ", " + status + ", " + type + ", " + mtu + ", " + dhcp + ", " + bridge + ", " + broadcastEnabled + ", " + portError + ", " + netconfRevision + ", " + Arrays.toString(assignedAddresses) + ", " + Arrays.toString(routes) + ", " + dns + ")";
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<>(); @Override
ArrayList<String> rNew = new ArrayList<>(); public boolean equals(Object o) {
for (VirtualNetworkRoute r : routes) {
rCurrent.add(r.toString()); if (!(o instanceof VirtualNetworkConfig)) {
return false;
} }
for (VirtualNetworkRoute r : cfg.routes) {
rNew.add(r.toString()); VirtualNetworkConfig cfg = (VirtualNetworkConfig) o;
}
Collections.sort(rCurrent);
Collections.sort(rNew);
boolean routesEqual = rCurrent.equals(rNew);
if (this.nwid != cfg.nwid) { if (this.nwid != cfg.nwid) {
Log.i(TAG, "nwid Changed. Old: " + Long.toHexString(this.nwid) + " (" + Long.toString(this.nwid) + "), " + Log.i(TAG, "NetworkID Changed. Old: " + StringUtils.networkIdToString(this.nwid) + " (" + this.nwid + "), " +
"New: " + Long.toHexString(cfg.nwid) + " (" + Long.toString(cfg.nwid) + ")"); "New: " + StringUtils.networkIdToString(cfg.nwid) + " (" + cfg.nwid + ")");
return false;
} }
if (this.mac != cfg.mac) { 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)) { 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)) { if (this.status != cfg.status) {
Log.i(TAG, "TYPE changed. Old " + this.type + ", New: " + cfg.type); 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) { 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) { if (this.dhcp != cfg.dhcp) {
Log.i(TAG, "DHCP Flag Changed. Old: " + this.dhcp + ", New: " + cfg.dhcp); Log.i(TAG, "DHCP Flag Changed. Old: " + this.dhcp + ", New: " + cfg.dhcp);
return false;
} }
if (this.bridge != cfg.bridge) { if (this.bridge != cfg.bridge) {
Log.i(TAG, "Bridge Flag Changed. Old: " + this.bridge + ", New: " + cfg.bridge); Log.i(TAG, "Bridge Flag Changed. Old: " + this.bridge + ", New: " + cfg.bridge);
return false;
} }
if (this.broadcastEnabled != cfg.broadcastEnabled) { 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);
return false;
} }
if (this.portError != cfg.portError) { if (this.portError != cfg.portError) {
Log.i(TAG, "Port Error Changed. Old: " + this.portError + ", New: " + this.portError); Log.i(TAG, "Port Error Changed. Old: " + this.portError + ", New: " + cfg.portError);
return false;
} }
if (this.enabled != cfg.enabled) { if (this.netconfRevision != cfg.netconfRevision) {
Log.i(TAG, "Enabled Changed. Old: " + this.enabled + ", New: " + this.enabled); Log.i(TAG, "NetConfRevision Changed. Old: " + this.netconfRevision + ", New: " + cfg.netconfRevision);
return false;
} }
if (!aaEqual) { 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);
Log.i(TAG, "Assigned Addresses Changed"); Log.i(TAG, "Assigned Addresses Changed");
Log.i(TAG, "Old:"); Log.i(TAG, "Old:");
for (String s : aaCurrent) { for (String s : aaCurrent) {
Log.i(TAG, " " + s); Log.i(TAG, " " + s);
} }
Log.i(TAG, "");
Log.i(TAG, "New:"); Log.i(TAG, "New:");
for (String s : aaNew) { for (String s : aaNew) {
Log.i(TAG, " " +s); 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, "Managed Routes Changed");
Log.i(TAG, "Old:"); Log.i(TAG, "Old:");
for (String s : rCurrent) { for (String s : rCurrent) {
Log.i(TAG, " " + s); Log.i(TAG, " " + s);
} }
Log.i(TAG, "");
Log.i(TAG, "New:"); Log.i(TAG, "New:");
for (String s : rNew) { for (String s : rNew) {
Log.i(TAG, " " + s); Log.i(TAG, " " + s);
} }
Log.i(TAG, "");
return false;
} }
boolean dnsEquals = false; boolean dnsEquals;
if (this.dns == null || cfg.dns == null) { if (this.dns == null) {
dnsEquals = true; //noinspection RedundantIfStatement
} else if (this.dns != null) { if (cfg.dns == null) {
dnsEquals = this.dns.equals(cfg.dns); dnsEquals = true;
} else {
dnsEquals = false;
}
} else {
if (cfg.dns == null) {
dnsEquals = false;
} else {
dnsEquals = this.dns.equals(cfg.dns);
}
} }
return this.nwid == cfg.nwid && if (!dnsEquals) {
this.mac == cfg.mac && return false;
this.name.equals(cfg.name) && }
this.status.equals(cfg.status) &&
this.type.equals(cfg.type) && return true;
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;
} }
@Override
public int compareTo(VirtualNetworkConfig cfg) { public int compareTo(VirtualNetworkConfig cfg) {
if(cfg.nwid == this.nwid) { return Long.compare(this.nwid, cfg.nwid);
return 0; }
} else {
return this.nwid > cfg.nwid ? 1 : -1; @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 * 64-bit ZeroTier network ID
*/ */
public final long networkId() { public long getNwid() {
return nwid; 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; return mac;
} }
/** /**
* Network name (from network configuration master) * Network name (from network configuration master)
*/ */
public final String name() { public String getName() {
return name; return name;
} }
/** /**
* Network configuration request status * Network configuration request status
*/ */
public final VirtualNetworkStatus networkStatus() { public VirtualNetworkStatus getStatus() {
return status; return status;
} }
/** /**
* Network type * Network type
*/ */
public final VirtualNetworkType networkType() { public VirtualNetworkType getType() {
return type; return type;
} }
/** /**
* Maximum interface MTU * Maximum interface MTU
*/ */
public final int mtu() { public int getMtu() {
return mtu; return mtu;
} }
@ -230,7 +335,7 @@ public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConf
* for security or other reasons. This is simply a netconf parameter that * for security or other reasons. This is simply a netconf parameter that
* means 'DHCP is available on this network.'</p> * means 'DHCP is available on this network.'</p>
*/ */
public final boolean isDhcpAvailable() { public boolean isDhcp() {
return dhcp; return dhcp;
} }
@ -240,21 +345,21 @@ public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConf
* <p>This is informational. If this is false, bridged packets will simply * <p>This is informational. If this is false, bridged packets will simply
* be dropped and bridging won't work.</p> * be dropped and bridging won't work.</p>
*/ */
public final boolean isBridgeEnabled() { public boolean isBridge() {
return bridge; return bridge;
} }
/** /**
* If true, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic * If true, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic
*/ */
public final boolean broadcastEnabled() { public boolean isBroadcastEnabled() {
return broadcastEnabled; return broadcastEnabled;
} }
/** /**
* If the network is in PORT_ERROR state, this is the error most recently returned by the port config callback * If the network is in PORT_ERROR state, this is the error most recently returned by the port config callback
*/ */
public final int portError() { public int getPortError() {
return portError; return portError;
} }
@ -263,12 +368,12 @@ public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConf
* *
* <p>If this is zero, it means we're still waiting for our netconf.</p> * <p>If this is zero, it means we're still waiting for our netconf.</p>
*/ */
public final long netconfRevision() { public long getNetconfRevision() {
return netconfRevision; 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 * 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. * of bits in the address netmask. Only the IP address and port are used.
@ -277,16 +382,21 @@ public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConf
* This is only used for ZeroTier-managed address assignments sent by the * This is only used for ZeroTier-managed address assignments sent by the
* virtual network's configuration master. * virtual network's configuration master.
*/ */
public final InetSocketAddress[] assignedAddresses() { public InetSocketAddress[] getAssignedAddresses() {
return assignedAddresses; return assignedAddresses;
} }
/** /**
* ZeroTier-assigned routes (in {@link com.zerotier.sdk.VirtualNetworkRoute} objects) * ZeroTier-assigned routes (in {@link VirtualNetworkRoute} objects)
*
* @return
*/ */
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;
}
} }

View file

@ -25,11 +25,11 @@
* LLC. Start here: http://www.zerotier.com/ * LLC. Start here: http://www.zerotier.com/
*/ */
package com.zerotier.sdk; package com.zerotier.sdk;
public interface VirtualNetworkConfigListener { public interface VirtualNetworkConfigListener {
/** /**
* Callback called to update virtual network port configuration * 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 * 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> * 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 * methods, as this could cause a deadlock in multithreaded or interrupt
* driven environments. * driven environments.
* *
@ -53,8 +53,8 @@ public interface VirtualNetworkConfigListener {
* @param config {@link VirtualNetworkConfig} object with the new configuration * @param config {@link VirtualNetworkConfig} object with the new configuration
* @return 0 on success * @return 0 on success
*/ */
public int onNetworkConfigurationUpdated( int onNetworkConfigurationUpdated(
long nwid, long nwid,
VirtualNetworkConfigOperation op, VirtualNetworkConfigOperation op,
VirtualNetworkConfig config); VirtualNetworkConfig config);
} }

View file

@ -24,26 +24,55 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks * redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/ * LLC. Start here: http://www.zerotier.com/
*/ */
package com.zerotier.sdk; package com.zerotier.sdk;
/**
* Virtual network configuration update type
*
* Defined in ZeroTierOne.h as ZT_VirtualNetworkConfigOperation
*/
public enum VirtualNetworkConfigOperation { public enum VirtualNetworkConfigOperation {
/** /**
* Network is coming up (either for the first time or after service restart) * 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 * Network configuration has been updated
*/ */
VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE, VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE(2),
/** /**
* Network is going down (not permanently) * Network is going down (not permanently)
*/ */
VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN, VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN(3),
/** /**
* Network is going down permanently (leave/delete) * 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);
}
}
} }

View file

@ -8,15 +8,48 @@ package com.zerotier.sdk;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList; 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> { 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 boolean equals(VirtualNetworkDNS o) { public VirtualNetworkDNS(String domain, ArrayList<InetSocketAddress> servers) {
if (o == null) return false; this.domain = domain;
return domain.equals(o.domain) && servers.equals(o.servers); 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;
}
VirtualNetworkDNS d = (VirtualNetworkDNS) o;
if (!domain.equals(d.domain)) {
return false;
}
if (!servers.equals(d.servers)) {
return false;
}
return true;
} }
@Override @Override
@ -24,7 +57,21 @@ public class VirtualNetworkDNS implements Comparable<VirtualNetworkDNS> {
return domain.compareTo(o.domain); return domain.compareTo(o.domain);
} }
public String getSearchDomain() { return domain; } @Override
public int hashCode() {
public ArrayList<InetSocketAddress> getServers() { return servers; } 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;
}
} }

View file

@ -28,17 +28,18 @@
package com.zerotier.sdk; package com.zerotier.sdk;
public interface VirtualNetworkFrameListener { public interface VirtualNetworkFrameListener {
/** /**
* Function to send a frame out to a virtual network port * Function to send a frame out to a virtual network port
* *
* @param nwid ZeroTier One network ID * @param nwid ZeroTier One network ID
* @param srcMac source MAC address * @param srcMac source MAC address
* @param destMac destination MAC address * @param destMac destination MAC address
* @param ethertype * @param etherType EtherType
* @param vlanId * @param vlanId VLAN ID
* @param frameData data to send * @param frameData data to send
*/ */
public void onVirtualNetworkFrame( void onVirtualNetworkFrame(
long nwid, long nwid,
long srcMac, long srcMac,
long destMac, long destMac,

View file

@ -29,80 +29,135 @@ package com.zerotier.sdk;
import java.net.InetSocketAddress; 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 * 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) * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway)
*/ */
public InetSocketAddress via; private final InetSocketAddress via;
/** /**
* Route flags * Route flags
*/ */
public int flags; private final int flags;
/** /**
* Route metric (not currently used) * Route metric (not currently used)
*/ */
public int metric; private final int metric;
@Override public VirtualNetworkRoute(InetSocketAddress target, InetSocketAddress via, int flags, int metric) {
public String toString() { this.target = target;
StringBuilder sb = new StringBuilder(); this.via = via;
sb.append(target.toString()); this.flags = flags;
if (via != null) { this.metric = metric;
sb.append(via.toString());
}
return sb.toString();
} }
@Override @Override
public int compareTo(VirtualNetworkRoute other) { public String toString() {
return this.toString().compareTo(other.toString()); return "VirtualNetworkRoute(" + target + ", " + via + ", " + flags + ", " + metric + ")";
} }
public boolean equals(VirtualNetworkRoute other) { @Override
boolean targetEquals = false; public int compareTo(VirtualNetworkRoute other) {
if (target == null && other.target == null) { throw new RuntimeException("Unimplemented");
targetEquals = true; }
}
else if (target == null && other.target != null) { @Override
targetEquals = false; public boolean equals(Object o) {
}
else if (target != null && other.target == null) { if (!(o instanceof VirtualNetworkRoute)) {
targetEquals = false; 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; boolean viaEquals;
if (via == null && other.via == null) { if (via == null) {
viaEquals = true; //noinspection RedundantIfStatement
} if (other.via == null) {
else if (via == null && other.via != null) { viaEquals = true;
viaEquals = false; } else {
} viaEquals = false;
else if (via != null && other.via == null) { }
viaEquals = false; } else {
} if (other.via == null) {
else { viaEquals = false;
viaEquals = via.toString().equals(other.via.toString()); } else {
viaEquals = via.equals(other.via);
}
} }
return viaEquals && targetEquals; if (!viaEquals) {
return false;
}
if (flags != other.flags) {
return false;
}
if (metric != other.metric) {
return false;
}
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;
} }
} }

View file

@ -24,41 +24,76 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks * redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/ * LLC. Start here: http://www.zerotier.com/
*/ */
package com.zerotier.sdk; package com.zerotier.sdk;
/**
* Virtual network status codes
*
* Defined in ZeroTierOne.h as ZT_VirtualNetworkStatus
*/
public enum VirtualNetworkStatus { public enum VirtualNetworkStatus {
/** /**
* Waiting for network configuration (also means revision == 0) * Waiting for network configuration (also means revision == 0)
*/ */
NETWORK_STATUS_REQUESTING_CONFIGURATION, NETWORK_STATUS_REQUESTING_CONFIGURATION(0),
/** /**
* Configuration received and we are authorized * Configuration received and we are authorized
*/ */
NETWORK_STATUS_OK, NETWORK_STATUS_OK(1),
/**
* Netconf master said SSO auth required.
*/
NETWORK_STATUS_AUTHENTICATION_REQUIRED,
/** /**
* Netconf master told us 'nope' * Netconf master told us 'nope'
*/ */
NETWORK_STATUS_ACCESS_DENIED, NETWORK_STATUS_ACCESS_DENIED(2),
/** /**
* Netconf master exists, but this virtual network does not * 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 * Initialization of network failed or other internal error
*/ */
NETWORK_STATUS_PORT_ERROR, NETWORK_STATUS_PORT_ERROR(4),
/** /**
* ZeroTier One version too old * 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);
}
}
} }

View file

@ -24,16 +24,41 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks * redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/ * LLC. Start here: http://www.zerotier.com/
*/ */
package com.zerotier.sdk; package com.zerotier.sdk;
/**
* Virtual network type codes
*
* Defined in ZeroTierOne.h as ZT_VirtualNetworkType
*/
public enum VirtualNetworkType { public enum VirtualNetworkType {
/** /**
* Private networks are authorized via certificates of membership * 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 * 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);
}
}
} }

View file

@ -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);
}
}

View file

@ -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");
}
}

21
one.cpp
View file

@ -2235,6 +2235,27 @@ int main(int argc,char **argv)
} }
} }
// Check and fix permissions on critical files at startup
try {
char p[4096];
OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "identity.secret", homeDir.c_str());
if (OSUtils::fileExists(p)) {
OSUtils::lockDownFile(p, false);
}
}
catch (...) {
}
try {
char p[4096];
OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "authtoken.secret", homeDir.c_str());
if (OSUtils::fileExists(p)) {
OSUtils::lockDownFile(p, false);
}
}
catch (...) {
}
// This can be removed once the new controller code has been around for many versions // This can be removed once the new controller code has been around for many versions
if (OSUtils::fileExists((homeDir + ZT_PATH_SEPARATOR_S + "controller.db").c_str(),true)) { if (OSUtils::fileExists((homeDir + ZT_PATH_SEPARATOR_S + "controller.db").c_str(),true)) {
fprintf(stderr,"%s: FATAL: an old controller.db exists in %s -- see instructions in controller/README.md for how to migrate!" ZT_EOL_S,argv[0],homeDir.c_str()); fprintf(stderr,"%s: FATAL: an old controller.db exists in %s -- see instructions in controller/README.md for how to migrate!" ZT_EOL_S,argv[0],homeDir.c_str());

View file

@ -257,6 +257,16 @@ void OSUtils::lockDownFile(const char *path,bool isDir)
CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread); CloseHandle(processInfo.hThread);
} }
// Remove 'Everyone' group from R/RX access
startupInfo.cb = sizeof(startupInfo);
memset(&startupInfo, 0, sizeof(STARTUPINFOA));
memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
if (CreateProcessA(NULL, (LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove:g Everyone /t /c /Q").c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) {
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
} }
#endif #endif
#endif #endif