Files

1445 lines
42 KiB
C++
Raw Permalink Normal View History

/*
* 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 "com_zerotierone_sdk_Node.h"
2023-03-07 16:50:34 -05:00
#include "ZT_jnicache.h"
#include "ZT_jniutils.h"
#include <ZeroTierOne.h>
2015-07-01 20:26:14 -07:00
#include "Mutex.hpp"
#include <map>
#include <string>
2023-03-07 16:50:34 -05:00
#include <cassert>
#include <cstring>
#include <cinttypes> // for PRId64
2023-03-07 16:50:34 -05:00
#define LOG_TAG "Node"
namespace {
struct JniRef
{
2023-03-07 16:50:34 -05:00
JniRef(
int64_t id,
JavaVM *jvm,
jobject dataStoreGetListenerLocalIn,
jobject dataStorePutListenerLocalIn,
jobject packetSenderLocalIn,
jobject eventListenerLocalIn,
jobject frameListenerLocalIn,
jobject configListenerLocalIn,
jobject pathCheckerLocalIn,
ZT_Node_Config *nc)
2023-03-07 16:50:34 -05:00
: id(id)
, jvm(jvm)
, node()
, dataStoreGetListener()
, dataStorePutListener()
, packetSender()
, eventListener()
, frameListener()
, configListener()
, pathChecker()
, nodeConfig(nc)
2023-03-07 16:50:34 -05:00
, inited() {
JNIEnv *env;
GETENV(env, jvm);
dataStoreGetListener = env->NewGlobalRef(dataStoreGetListenerLocalIn);
dataStorePutListener = env->NewGlobalRef(dataStorePutListenerLocalIn);
packetSender = env->NewGlobalRef(packetSenderLocalIn);
eventListener = env->NewGlobalRef(eventListenerLocalIn);
frameListener = env->NewGlobalRef(frameListenerLocalIn);
configListener = env->NewGlobalRef(configListenerLocalIn);
pathChecker = env->NewGlobalRef(pathCheckerLocalIn);
};
~JniRef()
{
2023-03-07 16:50:34 -05:00
JNIEnv *env;
GETENV(env, jvm);
env->DeleteGlobalRef(dataStoreGetListener);
env->DeleteGlobalRef(dataStorePutListener);
env->DeleteGlobalRef(packetSender);
env->DeleteGlobalRef(eventListener);
env->DeleteGlobalRef(frameListener);
env->DeleteGlobalRef(configListener);
2017-03-29 12:52:29 -07:00
env->DeleteGlobalRef(pathChecker);
delete nodeConfig;
nodeConfig = NULL;
}
int64_t id;
JavaVM *jvm;
ZT_Node *node;
jobject dataStoreGetListener;
jobject dataStorePutListener;
jobject packetSender;
2015-04-24 20:13:21 -07:00
jobject eventListener;
jobject frameListener;
jobject configListener;
2017-03-29 12:52:29 -07:00
jobject pathChecker;
ZT_Node_Config *nodeConfig;
2016-11-22 13:03:36 -08:00
2023-03-07 16:50:34 -05:00
bool inited;
bool finishInitializing();
};
//
// RAII construct for calling AttachCurrentThread and DetachCurrent automatically
//
struct ScopedJNIThreadAttacher {
JavaVM *jvm;
JNIEnv **env_p;
jint getEnvRet;
ScopedJNIThreadAttacher(JavaVM *jvmIn, JNIEnv **env_pIn, jint getEnvRetIn) :
jvm(jvmIn),
env_p(env_pIn),
getEnvRet(getEnvRetIn) {
if (getEnvRet != JNI_EDETACHED) {
return;
}
jint attachCurrentThreadRet;
if ((attachCurrentThreadRet = jvm->AttachCurrentThread(env_p, NULL)) != JNI_OK) {
LOGE("Error calling AttachCurrentThread: %d", attachCurrentThreadRet);
assert(false && "Error calling AttachCurrentThread");
}
}
~ScopedJNIThreadAttacher() {
if (getEnvRet != JNI_EDETACHED) {
return;
}
jint detachCurrentThreadRet;
if ((detachCurrentThreadRet = jvm->DetachCurrentThread()) != JNI_OK) {
LOGE("Error calling DetachCurrentThread: %d", detachCurrentThreadRet);
assert(false && "Error calling DetachCurrentThread");
}
}
};
2023-03-07 16:50:34 -05:00
/*
* This must return 0 on success. It can return any OS-dependent error code
* on failure, and this results in the network being placed into the
* PORT_ERROR state.
*/
int VirtualNetworkConfigFunctionCallback(
ZT_Node *node,
void *userData,
void *threadData,
uint64_t nwid,
2023-03-07 16:50:34 -05:00
void **nuptr,
enum ZT_VirtualNetworkConfigOperation operation,
const ZT_VirtualNetworkConfig *config)
{
2022-11-28 09:23:45 -05:00
LOGV("VirtualNetworkConfigFunctionCallback");
JniRef *ref = (JniRef*)userData;
2023-03-07 16:50:34 -05:00
assert(ref);
JNIEnv *env;
GETENV(env, ref->jvm);
if (env->ExceptionCheck()) {
LOGE("Unhandled pending exception");
return -100;
}
2018-02-12 09:29:44 -08:00
if (ref->configListener == NULL) {
LOGE("configListener is NULL");
2023-03-07 16:50:34 -05:00
return -101;
}
jobject operationObject = createVirtualNetworkConfigOperation(env, operation);
2023-03-07 16:50:34 -05:00
if(env->ExceptionCheck() || operationObject == NULL)
{
2023-03-07 16:50:34 -05:00
return -102;
}
if (config == NULL) {
LOGE("Config is NULL");
return -103;
}
jobject networkConfigObject = newNetworkConfig(env, *config);
2023-03-07 16:50:34 -05:00
if(env->ExceptionCheck() || networkConfigObject == NULL)
{
2023-03-07 16:50:34 -05:00
return -104;
}
2023-03-07 16:50:34 -05:00
jint ret = env->CallIntMethod(
2017-01-13 11:36:48 -08:00
ref->configListener,
2023-03-07 16:50:34 -05:00
VirtualNetworkConfigListener_onNetworkConfigurationUpdated_method,
(jlong)nwid, (jobject)operationObject, (jobject)networkConfigObject);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onNetworkConfigurationUpdated");
return -105;
}
return ret;
}
2015-11-02 19:18:55 -08:00
void VirtualNetworkFrameFunctionCallback(ZT_Node *node,
void *userData,
void *threadData,
uint64_t nwid,
2023-03-07 16:50:34 -05:00
void** nuptr,
uint64_t sourceMac,
uint64_t destMac,
unsigned int etherType,
unsigned int vlanid,
const void *frameData,
unsigned int frameLength)
{
LOGV("VirtualNetworkFrameFunctionCallback");
2018-02-12 09:29:44 -08:00
#ifndef NDEBUG
2023-03-07 16:50:34 -05:00
if (frameLength >= 14) {
unsigned char* local = (unsigned char*)frameData;
LOGV("Type Bytes: 0x%02x%02x", local[12], local[13]);
}
2018-02-12 09:29:44 -08:00
#endif
JniRef *ref = (JniRef*)userData;
2023-03-07 16:50:34 -05:00
assert(ref);
assert(ref->node == node);
2023-03-07 16:50:34 -05:00
JNIEnv *env;
jint getEnvRet;
assert(ref->jvm);
getEnvRet = ref->jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
if (!(getEnvRet == JNI_OK || getEnvRet == JNI_EDETACHED)) {
LOGE("Error calling GetEnv: %d", getEnvRet);
assert(false && "Error calling GetEnv");
}
2023-03-07 16:50:34 -05:00
//
// Thread might actually be detached.
//
// e.g:
// https://github.com/zerotier/ZeroTierOne/blob/91e7ce87f09ac1cfdeaf6ff22c3cedcd93574c86/node/Switch.cpp#L519
//
// Make sure to attach if needed
//
ScopedJNIThreadAttacher attacher{ref->jvm, &env, getEnvRet};
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Unhandled pending exception");
return;
}
2018-02-12 09:29:44 -08:00
if (ref->frameListener == NULL) {
LOGE("frameListener is NULL");
return;
}
2023-03-07 16:50:34 -05:00
const unsigned char *bytes = static_cast<const unsigned char*>(frameData);
jbyteArray dataArray = newByteArray(env, bytes, frameLength);
2015-06-01 20:03:28 -07:00
if(env->ExceptionCheck() || dataArray == NULL)
{
return;
}
env->CallVoidMethod(ref->frameListener, VirtualNetworkFrameListener_onVirtualNetworkFrame_method, (jlong)nwid, (jlong)sourceMac, (jlong)destMac, (jlong)etherType, (jlong)vlanid, (jbyteArray)dataArray);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onVirtualNetworkFrame");
2015-06-01 20:03:28 -07:00
return;
}
}
2015-11-02 19:18:55 -08:00
void EventCallback(ZT_Node *node,
void *userData,
void *threadData,
2017-01-13 11:36:48 -08:00
enum ZT_Event event,
2017-07-12 11:34:53 -07:00
const void *data) {
LOGV("EventCallback");
2017-07-12 11:34:53 -07:00
JniRef *ref = (JniRef *) userData;
2023-03-07 16:50:34 -05:00
assert(ref);
2017-07-12 11:34:53 -07:00
if (ref->node != node && event != ZT_EVENT_UP) {
2015-07-01 20:26:14 -07:00
LOGE("Nodes not equal. ref->node %p, node %p. Event: %d", ref->node, node, event);
2015-07-01 18:13:39 -07:00
return;
}
2023-03-07 16:50:34 -05:00
JNIEnv *env;
GETENV(env, ref->jvm);
if (env->ExceptionCheck()) {
LOGE("Unhandled pending exception");
return;
}
2018-02-12 09:29:44 -08:00
if (ref->eventListener == NULL) {
LOGE("eventListener is NULL");
return;
}
2015-04-24 20:13:21 -07:00
jobject eventObject = createEvent(env, event);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck() || eventObject == NULL) {
2015-04-24 20:13:21 -07:00
return;
}
2017-07-12 11:34:53 -07:00
switch (event) {
case ZT_EVENT_UP: {
LOGD("Event Up");
env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, (jobject)eventObject);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onEvent");
return;
}
2017-07-12 11:34:53 -07:00
break;
2015-04-24 20:13:21 -07:00
}
2017-07-12 11:34:53 -07:00
case ZT_EVENT_OFFLINE: {
LOGD("Event Offline");
env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, (jobject)eventObject);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onEvent");
return;
}
2017-07-12 11:34:53 -07:00
break;
}
case ZT_EVENT_ONLINE: {
LOGD("Event Online");
env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, (jobject)eventObject);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onEvent");
return;
}
2017-07-12 11:34:53 -07:00
break;
}
case ZT_EVENT_DOWN: {
LOGD("Event Down");
env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, (jobject)eventObject);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onEvent");
return;
}
2017-07-12 11:34:53 -07:00
break;
}
case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: {
LOGV("Identity Collision");
// call onEvent()
env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, (jobject)eventObject);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onEvent");
return;
}
2017-07-12 11:34:53 -07:00
}
break;
case ZT_EVENT_TRACE: {
LOGV("Trace Event");
// call onTrace()
2023-03-07 16:50:34 -05:00
if (data == NULL) {
break;
}
const char *message = (const char *) data;
jstring messageStr = env->NewStringUTF(message);
if (env->ExceptionCheck() || messageStr == NULL) {
LOGE("Exception creating new string");
return;
}
env->CallVoidMethod(ref->eventListener, EventListener_onTrace_method, (jstring)messageStr);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onTrace");
return;
2017-07-12 11:34:53 -07:00
}
}
break;
case ZT_EVENT_USER_MESSAGE:
case ZT_EVENT_REMOTE_TRACE:
2017-07-12 11:34:53 -07:00
break;
2015-04-24 20:13:21 -07:00
}
}
2017-07-12 11:34:53 -07:00
void StatePutFunction(
ZT_Node *node,
void *userData,
void *threadData,
enum ZT_StateObjectType type,
const uint64_t id[2],
const void *buffer,
int bufferLength) {
2023-03-07 16:50:34 -05:00
LOGV("StatePutFunction");
2017-07-12 11:34:53 -07:00
char p[4096] = {0};
bool secure = false;
2023-03-07 16:50:34 -05:00
int res = 0;
2017-07-12 11:34:53 -07:00
switch (type) {
case ZT_STATE_OBJECT_IDENTITY_PUBLIC:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "identity.public");
2017-07-12 11:34:53 -07:00
break;
case ZT_STATE_OBJECT_IDENTITY_SECRET:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "identity.secret");
2017-07-12 11:34:53 -07:00
secure = true;
break;
case ZT_STATE_OBJECT_PLANET:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "planet");
2017-07-12 11:34:53 -07:00
break;
case ZT_STATE_OBJECT_MOON:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "moons.d/%.16" PRIx64 ".moon", id[0]);
2017-07-12 11:34:53 -07:00
break;
case ZT_STATE_OBJECT_NETWORK_CONFIG:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "networks.d/%.16" PRIx64 ".conf", id[0]);
2017-07-12 11:34:53 -07:00
break;
case ZT_STATE_OBJECT_PEER:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "peers.d/%.10" PRIx64, id[0]);
2017-07-12 11:34:53 -07:00
break;
2023-03-07 16:50:34 -05:00
case ZT_STATE_OBJECT_NULL:
2017-07-12 11:34:53 -07:00
return;
}
2023-03-07 16:50:34 -05:00
if (!(0 <= res && res < sizeof(p))) {
LOGE("snprintf error: %d", res);
2018-02-12 09:29:44 -08:00
return;
}
2017-07-12 11:34:53 -07:00
JniRef *ref = (JniRef*)userData;
2023-03-07 16:50:34 -05:00
assert(ref);
JNIEnv *env;
GETENV(env, ref->jvm);
if (env->ExceptionCheck()) {
LOGE("Unhandled pending exception");
return;
}
2017-07-12 11:34:53 -07:00
2018-02-12 09:29:44 -08:00
if (ref->dataStorePutListener == NULL) {
LOGE("dataStorePutListener is NULL");
return;
}
2017-07-12 11:34:53 -07:00
jstring nameStr = env->NewStringUTF(p);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck() || nameStr == NULL) {
LOGE("Exception creating new string");
return;
}
2017-07-12 11:34:53 -07:00
if (bufferLength >= 0) {
LOGD("JNI: Write file: %s", p);
2023-03-07 16:50:34 -05:00
const unsigned char *bytes = static_cast<const unsigned char *>(buffer);
jbyteArray bufferObj = newByteArray(env, bytes, bufferLength);
2017-07-12 11:34:53 -07:00
if(env->ExceptionCheck() || bufferObj == NULL)
{
return;
}
2023-03-07 16:50:34 -05:00
int retval = env->CallIntMethod(ref->dataStorePutListener,
DataStorePutListener_onDataStorePut_method,
(jstring)nameStr, (jbyteArray)bufferObj, (jboolean)secure);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onDataStorePut");
return;
}
if (retval != 0) {
LOGE("onDataStorePut error: %d", retval);
}
2017-07-12 11:34:53 -07:00
} else {
LOGD("JNI: Delete file: %s", p);
int retval = env->CallIntMethod(ref->dataStorePutListener, DataStorePutListener_onDelete_method, (jstring)nameStr);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onDelete");
return;
}
if (retval != 0) {
LOGE("onDelete error: %d", retval);
}
2017-07-12 11:34:53 -07:00
}
}
2023-03-07 16:50:34 -05:00
/**
* This function should return the number of bytes actually stored to the
* buffer or -1 if the state object was not found or the buffer was too
* small to store it.
*/
2017-07-12 11:34:53 -07:00
int StateGetFunction(
ZT_Node *node,
void *userData,
void *threadData,
ZT_StateObjectType type,
const uint64_t id[2],
void *buffer,
unsigned int bufferLength) {
2023-03-07 16:50:34 -05:00
LOGV("StateGetFunction");
2017-07-12 11:34:53 -07:00
char p[4096] = {0};
2023-03-07 16:50:34 -05:00
int res = 0;
2017-07-12 11:34:53 -07:00
switch (type) {
case ZT_STATE_OBJECT_IDENTITY_PUBLIC:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "identity.public");
2017-07-12 11:34:53 -07:00
break;
case ZT_STATE_OBJECT_IDENTITY_SECRET:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "identity.secret");
2017-07-12 11:34:53 -07:00
break;
case ZT_STATE_OBJECT_PLANET:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "planet");
2017-07-12 11:34:53 -07:00
break;
case ZT_STATE_OBJECT_MOON:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "moons.d/%.16" PRIx64 ".moon", id[0]);
2017-07-12 11:34:53 -07:00
break;
case ZT_STATE_OBJECT_NETWORK_CONFIG:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "networks.d/%.16" PRIx64 ".conf", id[0]);
2017-07-12 11:34:53 -07:00
break;
case ZT_STATE_OBJECT_PEER:
2023-03-07 16:50:34 -05:00
res = snprintf(p, sizeof(p), "peers.d/%.10" PRIx64, id[0]);
2017-07-12 11:34:53 -07:00
break;
2023-03-07 16:50:34 -05:00
case ZT_STATE_OBJECT_NULL:
return -100;
2017-07-12 11:34:53 -07:00
}
2023-03-07 16:50:34 -05:00
if (!(0 <= res && res < sizeof(p))) {
LOGE("snprintf error: %d", res);
return -101;
2018-02-12 09:29:44 -08:00
}
JniRef *ref = (JniRef*)userData;
2023-03-07 16:50:34 -05:00
assert(ref);
JNIEnv *env;
GETENV(env, ref->jvm);
if (env->ExceptionCheck()) {
LOGE("Unhandled pending exception");
return -102;
}
2018-02-12 09:29:44 -08:00
if (ref->dataStoreGetListener == NULL) {
LOGE("dataStoreGetListener is NULL");
2023-03-07 16:50:34 -05:00
return -103;
2015-04-24 19:11:49 -07:00
}
2017-07-12 11:34:53 -07:00
jstring nameStr = env->NewStringUTF(p);
2023-03-07 16:50:34 -05:00
if(env->ExceptionCheck() || nameStr == NULL)
{
LOGE("Error creating name string object");
2023-03-07 16:50:34 -05:00
return -104; // out of memory
}
2023-03-07 16:50:34 -05:00
jbyteArray bufferObj = newByteArray(env, bufferLength);
if(env->ExceptionCheck() || bufferObj == NULL)
{
2023-03-07 16:50:34 -05:00
return -105;
}
2017-07-12 11:34:53 -07:00
LOGV("Calling onDataStoreGet(%s, %p)", p, buffer);
2017-07-12 13:12:45 -07:00
int retval = (int)env->CallLongMethod(
2017-07-12 11:34:53 -07:00
ref->dataStoreGetListener,
2023-03-07 16:50:34 -05:00
DataStoreGetListener_onDataStoreGet_method,
(jstring)nameStr,
(jbyteArray)bufferObj);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onDataStoreGet");
return -106;
}
2017-07-12 13:12:45 -07:00
LOGV("onDataStoreGet returned %d", retval);
if(retval > 0)
{
2023-03-07 16:50:34 -05:00
if (retval > bufferLength) {
LOGE("retval > bufferLength. retval: %d, bufferLength: %u", retval, bufferLength);
return -107;
}
2017-07-12 13:12:45 -07:00
void *data = env->GetPrimitiveArrayCritical(bufferObj, NULL);
memcpy(buffer, data, retval);
env->ReleasePrimitiveArrayCritical(bufferObj, data, 0);
}
return retval;
}
2023-03-07 16:50:34 -05:00
/**
* The function must return zero on success and may return any error code
* on failure. Note that success does not (of course) guarantee packet
* delivery. It only means that the packet appears to have been sent.
*/
2015-11-02 19:18:55 -08:00
int WirePacketSendFunction(ZT_Node *node,
void *userData,
void *threadData,
2017-07-12 11:34:53 -07:00
int64_t localSocket,
const struct sockaddr_storage *remoteAddress,
2015-04-24 19:43:17 -07:00
const void *buffer,
unsigned int bufferSize,
unsigned int ttl)
{
2023-03-07 16:50:34 -05:00
LOGV("WirePacketSendFunction(%" PRId64 ", %p, %p, %u, %u)", localSocket, remoteAddress, buffer, bufferSize, ttl);
JniRef *ref = (JniRef*)userData;
2023-03-07 16:50:34 -05:00
assert(ref);
assert(ref->node == node);
2023-03-07 16:50:34 -05:00
JNIEnv *env;
GETENV(env, ref->jvm);
if (env->ExceptionCheck()) {
LOGE("Unhandled pending exception");
return -100;
}
2018-02-12 09:29:44 -08:00
if (ref->packetSender == NULL) {
LOGE("packetSender is NULL");
2023-03-07 16:50:34 -05:00
return -101;
2015-04-24 19:43:17 -07:00
}
2017-01-13 11:36:48 -08:00
2023-03-07 16:50:34 -05:00
//
// may be NULL
//
jobject remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
return -102;
}
const unsigned char *bytes = static_cast<const unsigned char *>(buffer);
jbyteArray bufferObj = newByteArray(env, bytes, bufferSize);
if (env->ExceptionCheck() || bufferObj == NULL)
{
return -103;
}
int retval = env->CallIntMethod(ref->packetSender, PacketSender_onSendPacketRequested_method, (jlong)localSocket, (jobject)remoteAddressObj, (jbyteArray)bufferObj, (jint)0);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onSendPacketRequested");
return -104;
}
2015-05-27 20:42:54 -07:00
LOGV("JNI Packet Sender returned: %d", retval);
2015-05-27 20:42:54 -07:00
return retval;
}
2023-03-07 16:50:34 -05:00
/**
* This function must return nonzero (true) if the path should be used.
*/
2017-03-29 12:52:29 -07:00
int PathCheckFunction(ZT_Node *node,
void *userPtr,
void *threadPtr,
uint64_t address,
2017-07-12 11:34:53 -07:00
int64_t localSocket,
2017-03-29 12:52:29 -07:00
const struct sockaddr_storage *remoteAddress)
{
2023-03-07 16:50:34 -05:00
LOGV("PathCheckFunction");
2017-03-29 12:52:29 -07:00
JniRef *ref = (JniRef*)userPtr;
2023-03-07 16:50:34 -05:00
assert(ref);
2017-03-29 12:52:29 -07:00
assert(ref->node == node);
if(ref->pathChecker == NULL) {
return true;
}
2023-03-07 16:50:34 -05:00
JNIEnv *env;
GETENV(env, ref->jvm);
2017-03-29 12:52:29 -07:00
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Unhandled pending exception");
2017-03-29 12:52:29 -07:00
return true;
}
//
2023-03-07 16:50:34 -05:00
// may be NULL
//
2023-03-07 16:50:34 -05:00
jobject remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
if (env->ExceptionCheck()) {
return true;
2017-03-29 12:52:29 -07:00
}
jboolean ret = env->CallBooleanMethod(ref->pathChecker, PathChecker_onPathCheck_method, (jlong)address, (jlong)localSocket, (jobject)remoteAddressObj);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling onPathCheck");
return true;
}
return ret;
2017-03-29 12:52:29 -07:00
}
2023-03-07 16:50:34 -05:00
/**
* It must return a nonzero (true) value if the result buffer has been filled with an address.
*/
2017-03-29 12:52:29 -07:00
int PathLookupFunction(ZT_Node *node,
void *userPtr,
void *threadPtr,
uint64_t address,
int ss_family,
struct sockaddr_storage *result)
{
2023-03-07 16:50:34 -05:00
LOGV("PathLookupFunction");
2017-03-29 12:52:29 -07:00
JniRef *ref = (JniRef*)userPtr;
2023-03-07 16:50:34 -05:00
assert(ref);
2017-03-29 12:52:29 -07:00
assert(ref->node == node);
if(ref->pathChecker == NULL) {
return false;
}
2023-03-07 16:50:34 -05:00
JNIEnv *env;
GETENV(env, ref->jvm);
2017-03-29 12:52:29 -07:00
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Unhandled pending exception");
return false;
}
//
// may be NULL
//
jobject sockAddressObject = env->CallObjectMethod(ref->pathChecker, PathChecker_onPathLookup_method, (jlong)address, (jint)ss_family);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Unable to call onPathLookup implementation");
2017-03-29 12:52:29 -07:00
return false;
}
if(sockAddressObject == NULL)
{
LOGE("Unable to call onPathLookup implementation");
return false;
}
2023-03-07 16:50:34 -05:00
*result = fromSocketAddressObject(env, sockAddressObject);
if (env->ExceptionCheck() || isSocketAddressEmpty(*result)) {
2017-03-29 12:52:29 -07:00
return false;
}
return true;
}
typedef std::map<int64_t, JniRef*> NodeMap;
2023-03-07 16:50:34 -05:00
NodeMap nodeMap;
2015-07-01 20:26:14 -07:00
ZeroTier::Mutex nodeMapMutex;
2015-04-23 22:46:54 -07:00
2023-03-07 16:50:34 -05:00
bool isInited(int64_t nodeId) {
ZeroTier::Mutex::Lock lock(nodeMapMutex);
NodeMap::iterator found = nodeMap.find(nodeId);
if (found == nodeMap.end()) {
//
// not in map yet, or has been removed from map
//
return false;
}
JniRef *ref = found->second;
assert(ref);
return ref->inited;
}
bool JniRef::finishInitializing() {
ZeroTier::Mutex::Lock lock(nodeMapMutex);
NodeMap::iterator found = nodeMap.find(id);
if (found != nodeMap.end()) {
//
// already in map
//
LOGE("Cannot finish initializing; node is already in map");
return false;
}
nodeMap.insert(std::make_pair(id, this));
assert(!inited);
inited = true;
return true;
}
ZT_Node* findNode(int64_t nodeId)
2015-04-23 22:46:54 -07:00
{
2015-07-01 20:26:14 -07:00
ZeroTier::Mutex::Lock lock(nodeMapMutex);
2015-04-23 22:46:54 -07:00
NodeMap::iterator found = nodeMap.find(nodeId);
2023-03-07 16:50:34 -05:00
assert(found != nodeMap.end());
JniRef *ref = found->second;
assert(ref);
return ref->node;
}
JniRef *removeRef(int64_t nodeId) {
ZeroTier::Mutex::Lock lock(nodeMapMutex);
NodeMap::iterator found = nodeMap.find(nodeId);
if (found == nodeMap.end()) {
return nullptr;
2015-04-23 22:46:54 -07:00
}
2023-03-07 16:50:34 -05:00
JniRef *ref = found->second;
assert(ref);
nodeMap.erase(nodeId);
return ref;
2015-04-23 22:46:54 -07:00
}
}
2023-03-07 16:50:34 -05:00
#ifdef __cplusplus
extern "C" {
#endif
2017-01-13 11:36:48 -08:00
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
2023-03-07 16:50:34 -05:00
setupJNICache(vm);
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
{
2023-03-07 16:50:34 -05:00
teardownJNICache(vm);
}
/*
* Class: com_zerotier_sdk_Node
* Method: node_init
2023-03-07 16:50:34 -05:00
* 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(
2023-03-07 16:50:34 -05:00
JNIEnv *env, jobject obj, jlong now, jobject dataStoreGetListener,
jobject dataStorePutListener, jobject packetSender, jobject eventListener,
jobject frameListener, jobject configListener,
jobject pathChecker)
{
LOGV("Creating ZT_Node struct");
2023-03-07 16:50:34 -05:00
jobject resultObject = ResultCode_RESULT_OK_enum;
JavaVM *vm;
GETJAVAVM(env, vm);
assert(dataStoreGetListener != NULL);
assert(dataStorePutListener != NULL);
assert(packetSender != NULL);
assert(frameListener != NULL);
assert(configListener != NULL);
assert(eventListener != NULL);
//
// OPTIONAL, pathChecker may be NULL
//
// assert(pathChecker != NULL);
ZT_Node_Callbacks callbacks{};
callbacks.stateGetFunction = &StateGetFunction;
callbacks.statePutFunction = &StatePutFunction;
callbacks.wirePacketSendFunction = &WirePacketSendFunction;
callbacks.virtualNetworkFrameFunction = &VirtualNetworkFrameFunctionCallback;
callbacks.virtualNetworkConfigFunction = &VirtualNetworkConfigFunctionCallback;
callbacks.eventCallback = &EventCallback;
callbacks.pathCheckFunction = &PathCheckFunction;
callbacks.pathLookupFunction = &PathLookupFunction;
ZT_Node_Config *nodeConfig = new ZT_Node_Config();
nodeConfig->enableEncryptedHello = 0;
nodeConfig->lowBandwidthMode = 0;
2023-03-07 16:50:34 -05:00
//
// a bit of a confusing dance here where ref and node both know about each other
//
JniRef *ref = new JniRef(
now,
vm,
dataStoreGetListener,
dataStorePutListener,
packetSender,
eventListener,
frameListener,
configListener,
pathChecker,
nodeConfig);
ZT_Node *node;
ZT_ResultCode rc = ZT_Node_new(
&node,
nodeConfig,
ref,
NULL,
2023-03-07 16:50:34 -05:00
&callbacks,
(int64_t)now);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception creating Node");
2023-03-07 16:50:34 -05:00
if(node)
{
ZT_Node_delete(node);
node = NULL;
}
delete ref;
ref = NULL;
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
if(rc != ZT_RESULT_OK)
{
LOGE("Error creating Node: %d", rc);
resultObject = createResultObject(env, rc);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck() || resultObject == NULL) {
return NULL;
}
if(node)
{
ZT_Node_delete(node);
node = NULL;
}
delete ref;
ref = NULL;
return resultObject;
}
2023-03-07 16:50:34 -05:00
//
// node is now updated
//
ref->node = node;
2023-03-07 16:50:34 -05:00
if (!ref->finishInitializing()) {
LOGE("finishInitializing() failed");
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
2017-01-13 11:36:48 -08:00
return resultObject;
}
2023-03-07 16:50:34 -05:00
/*
* Class: com_zerotier_sdk_Node
* Method: node_isInited
* Signature: (J)Z
*/
JNIEXPORT jboolean JNICALL Java_com_zerotier_sdk_Node_node_1isInited
(JNIEnv *env, jobject obj, jlong nodeId) {
return isInited(nodeId);
}
/*
* Class: com_zerotier_sdk_Node
* Method: node_delete
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_com_zerotier_sdk_Node_node_1delete(
2015-04-23 23:09:30 -07:00
JNIEnv *env, jobject obj, jlong id)
{
LOGV("Destroying ZT_Node struct");
int64_t nodeId = (int64_t)id;
2023-03-07 16:50:34 -05:00
JniRef *ref = removeRef(nodeId);
if (!ref) {
return;
2015-07-01 20:26:14 -07:00
}
2023-03-07 16:50:34 -05:00
ZT_Node_delete(ref->node);
2023-03-07 16:50:34 -05:00
delete ref;
}
/*
* Class: com_zerotier_sdk_Node
* Method: processVirtualNetworkFrame
* Signature: (JJJJJII[B[J)Lcom/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame(
2017-01-13 11:36:48 -08:00
JNIEnv *env, jobject obj,
jlong id,
jlong in_now,
jlong in_nwid,
jlong in_sourceMac,
jlong in_destMac,
jint in_etherType,
jint in_vlanId,
jbyteArray in_frameData,
jlongArray out_nextBackgroundTaskDeadline)
{
int64_t nodeId = (int64_t) id;
2017-01-13 11:36:48 -08:00
ZT_Node *node = findNode(nodeId);
unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline);
if(nbtd_len < 1)
{
// array for next background task length has 0 elements!
2023-03-07 16:50:34 -05:00
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
int64_t now = (int64_t)in_now;
uint64_t nwid = (uint64_t)in_nwid;
uint64_t sourceMac = (uint64_t)in_sourceMac;
uint64_t destMac = (uint64_t)in_destMac;
unsigned int etherType = (unsigned int)in_etherType;
unsigned int vlanId = (unsigned int)in_vlanId;
unsigned int frameLength = env->GetArrayLength(in_frameData);
void *frameData = env->GetPrimitiveArrayCritical(in_frameData, NULL);
2023-03-07 16:50:34 -05:00
//
// need local copy of frameData because arbitrary code may run in ZT_Node_processVirtualNetworkFrame and no other JNI work may happen between GetPrimitiveArrayCritical / ReleasePrimitiveArrayCritical
//
void *localData = malloc(frameLength);
memcpy(localData, frameData, frameLength);
env->ReleasePrimitiveArrayCritical(in_frameData, frameData, 0);
int64_t nextBackgroundTaskDeadline = 0;
ZT_ResultCode rc = ZT_Node_processVirtualNetworkFrame(
node,
NULL,
now,
nwid,
sourceMac,
destMac,
etherType,
vlanId,
(const void*)localData,
frameLength,
&nextBackgroundTaskDeadline);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling ZT_Node_processVirtualNetworkFrame");
free(localData);
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
if (rc != ZT_RESULT_OK) {
LOGE("ZT_Node_processVirtualNetworkFrame returned: %d", rc);
}
free(localData);
jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0);
return createResultObject(env, rc);
}
2015-04-22 20:21:12 -07:00
/*
* Class: com_zerotier_sdk_Node
2015-04-22 20:21:12 -07:00
* Method: processWirePacket
2023-03-07 16:50:34 -05:00
* Signature: (JJJLjava/net/InetSocketAddress;[B[J)Lcom/zerotier/sdk/ResultCode;
2015-04-22 20:21:12 -07:00
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
2017-01-13 11:36:48 -08:00
JNIEnv *env, jobject obj,
2015-04-22 20:21:12 -07:00
jlong id,
2017-01-13 11:36:48 -08:00
jlong in_now,
2017-07-12 11:34:53 -07:00
jlong in_localSocket,
2015-04-22 20:21:12 -07:00
jobject in_remoteAddress,
jbyteArray in_packetData,
jlongArray out_nextBackgroundTaskDeadline)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
2015-04-22 20:21:12 -07:00
2017-07-12 11:34:53 -07:00
unsigned int nbtd_len = (unsigned int)env->GetArrayLength(out_nextBackgroundTaskDeadline);
2015-04-22 20:21:12 -07:00
if(nbtd_len < 1)
{
2015-06-03 21:29:07 -07:00
LOGE("nbtd_len < 1");
2023-03-07 16:50:34 -05:00
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
2015-04-22 20:21:12 -07:00
}
int64_t now = (int64_t)in_now;
2015-04-22 20:21:12 -07:00
2023-03-07 16:50:34 -05:00
sockaddr_storage remoteAddress = fromSocketAddressObject(env, in_remoteAddress);
if (env->ExceptionCheck() || isSocketAddressEmpty(remoteAddress)) {
return NULL;
2015-04-22 20:21:12 -07:00
}
2017-07-12 11:34:53 -07:00
unsigned int packetLength = (unsigned int)env->GetArrayLength(in_packetData);
2015-07-01 20:26:14 -07:00
if(packetLength == 0)
{
LOGE("Empty packet?!?");
2023-03-07 16:50:34 -05:00
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
2015-07-01 20:26:14 -07:00
}
void *packetData = env->GetPrimitiveArrayCritical(in_packetData, NULL);
2023-03-07 16:50:34 -05:00
//
// need local copy of packetData because arbitrary code may run in ZT_Node_processWirePacket and no other JNI work may happen between GetPrimitiveArrayCritical / ReleasePrimitiveArrayCritical
//
void *localData = malloc(packetLength);
memcpy(localData, packetData, packetLength);
env->ReleasePrimitiveArrayCritical(in_packetData, packetData, 0);
2015-04-22 20:21:12 -07:00
int64_t nextBackgroundTaskDeadline = 0;
2015-04-22 20:21:12 -07:00
ZT_ResultCode rc = ZT_Node_processWirePacket(
2015-04-22 20:21:12 -07:00
node,
NULL,
2015-04-22 20:21:12 -07:00
now,
2017-07-12 11:34:53 -07:00
in_localSocket,
2015-04-22 20:21:12 -07:00
&remoteAddress,
localData,
2015-04-22 20:21:12 -07:00
packetLength,
&nextBackgroundTaskDeadline);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling ZT_Node_processWirePacket");
free(localData);
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
2017-01-13 11:36:48 -08:00
if(rc != ZT_RESULT_OK)
2015-06-03 21:29:07 -07:00
{
LOGE("ZT_Node_processWirePacket returned: %d", rc);
2015-06-03 21:29:07 -07:00
}
2015-04-22 20:21:12 -07:00
free(localData);
2015-04-22 20:21:12 -07:00
jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0);
2015-04-22 20:21:12 -07:00
return createResultObject(env, rc);
2015-04-22 20:21:12 -07:00
}
2015-04-22 20:25:35 -07:00
/*
* Class: com_zerotier_sdk_Node
2015-04-22 20:25:35 -07:00
* Method: processBackgroundTasks
* Signature: (JJ[J)Lcom/zerotier/sdk/ResultCode;
2015-04-22 20:25:35 -07:00
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processBackgroundTasks(
2017-01-13 11:36:48 -08:00
JNIEnv *env, jobject obj,
2015-04-22 20:25:35 -07:00
jlong id,
jlong in_now,
jlongArray out_nextBackgroundTaskDeadline)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
2015-04-22 20:25:35 -07:00
unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline);
if(nbtd_len < 1)
{
2023-03-07 16:50:34 -05:00
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
2015-04-22 20:25:35 -07:00
}
int64_t now = (int64_t)in_now;
int64_t nextBackgroundTaskDeadline = 0;
2015-04-22 20:25:35 -07:00
ZT_ResultCode rc = ZT_Node_processBackgroundTasks(node, NULL, now, &nextBackgroundTaskDeadline);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling ZT_Node_processBackgroundTasks");
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
if (rc != ZT_RESULT_OK) {
LOGE("ZT_Node_processBackgroundTasks returned: %d", rc);
}
2015-04-22 20:25:35 -07:00
jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
2015-04-22 20:25:35 -07:00
outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0);
2015-04-22 20:25:35 -07:00
return createResultObject(env, rc);
}
2015-04-22 20:29:34 -07:00
/*
* Class: com_zerotier_sdk_Node
2015-04-22 20:29:34 -07:00
* Method: join
* Signature: (JJ)Lcom/zerotier/sdk/ResultCode;
2015-04-22 20:29:34 -07:00
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_join(
2015-04-23 23:09:30 -07:00
JNIEnv *env, jobject obj, jlong id, jlong in_nwid)
2015-04-22 20:29:34 -07:00
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
2015-04-22 20:29:34 -07:00
uint64_t nwid = (uint64_t)in_nwid;
ZT_ResultCode rc = ZT_Node_join(node, nwid, NULL, NULL);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling ZT_Node_join");
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
2015-04-22 20:29:34 -07:00
return createResultObject(env, rc);
}
/*
* Class: com_zerotier_sdk_Node
2015-04-22 20:29:34 -07:00
* Method: leave
* Signature: (JJ)Lcom/zerotier/sdk/ResultCode;
2015-04-22 20:29:34 -07:00
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_leave(
2015-04-23 23:09:30 -07:00
JNIEnv *env, jobject obj, jlong id, jlong in_nwid)
2015-04-22 20:29:34 -07:00
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
2015-04-22 20:29:34 -07:00
uint64_t nwid = (uint64_t)in_nwid;
ZT_ResultCode rc = ZT_Node_leave(node, nwid, NULL, NULL);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling ZT_Node_leave");
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
2017-01-13 11:36:48 -08:00
2015-04-22 20:29:34 -07:00
return createResultObject(env, rc);
}
/*
* Class: com_zerotier_sdk_Node
* Method: multicastSubscribe
* Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastSubscribe(
2017-01-13 11:36:48 -08:00
JNIEnv *env, jobject obj,
jlong id,
jlong in_nwid,
jlong in_multicastGroup,
jlong in_multicastAdi)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
uint64_t nwid = (uint64_t)in_nwid;
uint64_t multicastGroup = (uint64_t)in_multicastGroup;
unsigned long multicastAdi = (unsigned long)in_multicastAdi;
ZT_ResultCode rc = ZT_Node_multicastSubscribe(
node, NULL, nwid, multicastGroup, multicastAdi);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling ZT_Node_multicastSubscribe");
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
return createResultObject(env, rc);
}
/*
* Class: com_zerotier_sdk_Node
* Method: multicastUnsubscribe
* Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastUnsubscribe(
2017-01-13 11:36:48 -08:00
JNIEnv *env, jobject obj,
jlong id,
jlong in_nwid,
jlong in_multicastGroup,
jlong in_multicastAdi)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
uint64_t nwid = (uint64_t)in_nwid;
uint64_t multicastGroup = (uint64_t)in_multicastGroup;
unsigned long multicastAdi = (unsigned long)in_multicastAdi;
ZT_ResultCode rc = ZT_Node_multicastUnsubscribe(
node, nwid, multicastGroup, multicastAdi);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling ZT_Node_multicastUnsubscribe");
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
return createResultObject(env, rc);
}
/*
* Class: com_zerotier_sdk_Node
* Method: orbit
* Signature: (JJJ)Lcom/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_orbit(
JNIEnv *env, jobject obj,
jlong id,
jlong in_moonWorldId,
jlong in_moonSeed)
{
int64_t nodeId = (int64_t)id;
ZT_Node *node = findNode(nodeId);
uint64_t moonWorldId = (uint64_t)in_moonWorldId;
uint64_t moonSeed = (uint64_t)in_moonSeed;
ZT_ResultCode rc = ZT_Node_orbit(node, NULL, moonWorldId, moonSeed);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling ZT_Node_orbit");
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
return createResultObject(env, rc);
}
/*
* Class: com_zerotier_sdk_Node
* Method: deorbit
* Signature: (JJ)L/com/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_deorbit(
JNIEnv *env, jobject obj,
jlong id,
jlong in_moonWorldId)
{
int64_t nodeId = (int64_t)id;
ZT_Node *node = findNode(nodeId);
uint64_t moonWorldId = (uint64_t)in_moonWorldId;
ZT_ResultCode rc = ZT_Node_deorbit(node, NULL, moonWorldId);
2023-03-07 16:50:34 -05:00
if (env->ExceptionCheck()) {
LOGE("Exception calling ZT_Node_deorbit");
return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
}
return createResultObject(env, rc);
}
2015-04-22 21:29:45 -07:00
/*
* Class: com_zerotier_sdk_Node
2015-04-22 21:30:37 -07:00
* Method: address
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_com_zerotier_sdk_Node_address(
2015-04-23 23:09:30 -07:00
JNIEnv *env , jobject obj, jlong id)
2015-04-22 21:30:37 -07:00
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
2015-04-22 21:30:37 -07:00
uint64_t address = ZT_Node_address(node);
2015-04-22 21:30:37 -07:00
return (jlong)address;
}
/*
* Class: com_zerotier_sdk_Node
* Method: status
* Signature: (J)Lcom/zerotier/sdk/NodeStatus;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_status
(JNIEnv *env, jobject obj, jlong id)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
ZT_NodeStatus nodeStatus;
ZT_Node_status(node, &nodeStatus);
2023-03-07 16:50:34 -05:00
return newNodeStatus(env, nodeStatus);
}
/*
* Class: com_zerotier_sdk_Node
* Method: networkConfig
2023-03-07 16:50:34 -05:00
* Signature: (JJ)Lcom/zerotier/sdk/VirtualNetworkConfig;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_networkConfig(
2015-04-23 23:09:30 -07:00
JNIEnv *env, jobject obj, jlong id, jlong nwid)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
ZT_VirtualNetworkConfig *vnetConfig = ZT_Node_networkConfig(node, nwid);
2023-03-07 16:50:34 -05:00
if (vnetConfig == NULL) {
LOGE("vnetConfig == NULL");
return NULL;
}
2017-01-13 11:36:48 -08:00
jobject vnetConfigObject = newNetworkConfig(env, *vnetConfig);
ZT_Node_freeQueryResult(node, vnetConfig);
return vnetConfigObject;
}
/*
* Class: com_zerotier_sdk_Node
2015-04-22 21:29:45 -07:00
* Method: version
2023-03-07 16:50:34 -05:00
* Signature: ()Lcom/zerotier/sdk/Version;
2015-04-22 21:29:45 -07:00
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_version(
2015-04-23 23:09:30 -07:00
JNIEnv *env, jobject obj)
2015-04-22 21:29:45 -07:00
{
int major = 0;
int minor = 0;
int revision = 0;
2016-07-07 20:07:07 -07:00
ZT_version(&major, &minor, &revision);
2015-04-22 21:29:45 -07:00
2016-07-07 20:07:07 -07:00
return newVersion(env, major, minor, revision);
2015-04-22 21:29:45 -07:00
}
2015-04-22 20:29:34 -07:00
/*
* Class: com_zerotier_sdk_Node
* Method: peers
* Signature: (J)[Lcom/zerotier/sdk/Peer;
*/
JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers(
JNIEnv *env, jobject obj, jlong id)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
2015-04-24 18:06:26 -07:00
ZT_PeerList *peerList = ZT_Node_peers(node);
2017-01-13 11:36:48 -08:00
2015-04-24 18:06:26 -07:00
if(peerList == NULL)
{
LOGE("ZT_Node_peers returned NULL");
2015-04-24 18:06:26 -07:00
return NULL;
}
2023-03-07 16:50:34 -05:00
jobjectArray peerArrayObj = newPeerArray(env, peerList->peers, peerList->peerCount);
2015-04-24 18:06:26 -07:00
ZT_Node_freeQueryResult(node, peerList);
peerList = NULL;
return peerArrayObj;
}
/*
* Class: com_zerotier_sdk_Node
2023-03-07 16:50:34 -05:00
* Method: networkConfigs
* Signature: (J)[Lcom/zerotier/sdk/VirtualNetworkConfig;
*/
2023-03-07 16:50:34 -05:00
JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networkConfigs(
JNIEnv *env, jobject obj, jlong id)
{
int64_t nodeId = (int64_t) id;
ZT_Node *node = findNode(nodeId);
ZT_VirtualNetworkList *networkList = ZT_Node_networks(node);
if(networkList == NULL)
{
2023-03-07 16:50:34 -05:00
LOGE("ZT_Node_networks returned NULL");
return NULL;
}
2023-03-07 16:50:34 -05:00
jobjectArray networkListObject = newVirtualNetworkConfigArray(env, networkList->networks, networkList->networkCount);
ZT_Node_freeQueryResult(node, networkList);
return networkListObject;
}
#ifdef __cplusplus
} // extern "C"
2023-03-07 16:50:34 -05:00
#endif