com_zerotierone_sdk_Node.cpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2015 ZeroTier, Inc.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #include "com_zerotierone_sdk_Node.h"
  28. #include "ZT_jnicache.h"
  29. #include "ZT_jniutils.h"
  30. #include <ZeroTierOne.h>
  31. #include "Mutex.hpp"
  32. #include <map>
  33. #include <string>
  34. #include <cassert>
  35. #include <cstring>
  36. #define LOG_TAG "Node"
  37. namespace {
  38. struct JniRef
  39. {
  40. JniRef()
  41. : jvm(NULL)
  42. , node(NULL)
  43. , dataStoreGetListener(NULL)
  44. , dataStorePutListener(NULL)
  45. , packetSender(NULL)
  46. , eventListener(NULL)
  47. , frameListener(NULL)
  48. , configListener(NULL)
  49. , pathChecker(NULL)
  50. , callbacks(NULL)
  51. {
  52. callbacks = (ZT_Node_Callbacks*)malloc(sizeof(ZT_Node_Callbacks));
  53. memset(callbacks, 0, sizeof(ZT_Node_Callbacks));
  54. }
  55. ~JniRef()
  56. {
  57. JNIEnv *env = NULL;
  58. jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
  59. env->DeleteGlobalRef(dataStoreGetListener);
  60. env->DeleteGlobalRef(dataStorePutListener);
  61. env->DeleteGlobalRef(packetSender);
  62. env->DeleteGlobalRef(eventListener);
  63. env->DeleteGlobalRef(frameListener);
  64. env->DeleteGlobalRef(configListener);
  65. env->DeleteGlobalRef(pathChecker);
  66. free(callbacks);
  67. callbacks = NULL;
  68. }
  69. int64_t id;
  70. JavaVM *jvm;
  71. ZT_Node *node;
  72. jobject dataStoreGetListener;
  73. jobject dataStorePutListener;
  74. jobject packetSender;
  75. jobject eventListener;
  76. jobject frameListener;
  77. jobject configListener;
  78. jobject pathChecker;
  79. ZT_Node_Callbacks *callbacks;
  80. };
  81. int VirtualNetworkConfigFunctionCallback(
  82. ZT_Node *node,
  83. void *userData,
  84. void *threadData,
  85. uint64_t nwid,
  86. void **,
  87. enum ZT_VirtualNetworkConfigOperation operation,
  88. const ZT_VirtualNetworkConfig *config)
  89. {
  90. LOGV("VirtualNetworkConfigFunctionCallback");
  91. JniRef *ref = (JniRef*)userData;
  92. JNIEnv *env = NULL;
  93. ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
  94. if (ref->configListener == NULL) {
  95. LOGE("configListener is NULL");
  96. return -100;
  97. }
  98. jobject operationObject = createVirtualNetworkConfigOperation(env, operation);
  99. if(env->ExceptionCheck() || operationObject == NULL)
  100. {
  101. return -101;
  102. }
  103. jobject networkConfigObject = newNetworkConfig(env, *config);
  104. if(networkConfigObject == NULL)
  105. {
  106. LOGE("Error creating VirtualNetworkConfig object");
  107. return -102;
  108. }
  109. return env->CallIntMethod(
  110. ref->configListener,
  111. VirtualNetworkConfigListener_onNetworkConfigurationUpdated_method,
  112. (jlong)nwid, operationObject, networkConfigObject);
  113. }
  114. void VirtualNetworkFrameFunctionCallback(ZT_Node *node,
  115. void *userData,
  116. void *threadData,
  117. uint64_t nwid,
  118. void**,
  119. uint64_t sourceMac,
  120. uint64_t destMac,
  121. unsigned int etherType,
  122. unsigned int vlanid,
  123. const void *frameData,
  124. unsigned int frameLength)
  125. {
  126. LOGV("VirtualNetworkFrameFunctionCallback");
  127. #ifndef NDEBUG
  128. unsigned char* local = (unsigned char*)frameData;
  129. LOGV("Type Bytes: 0x%02x%02x", local[12], local[13]);
  130. #endif
  131. JniRef *ref = (JniRef*)userData;
  132. assert(ref->node == node);
  133. JNIEnv *env = NULL;
  134. ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
  135. if (ref->frameListener == NULL) {
  136. LOGE("frameListener is NULL");
  137. return;
  138. }
  139. jbyteArray dataArray = env->NewByteArray(frameLength);
  140. if(env->ExceptionCheck() || dataArray == NULL)
  141. {
  142. LOGE("Couldn't create frame data array");
  143. return;
  144. }
  145. void *data = env->GetPrimitiveArrayCritical(dataArray, NULL);
  146. memcpy(data, frameData, frameLength);
  147. env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
  148. if(env->ExceptionCheck())
  149. {
  150. LOGE("Error setting frame data to array");
  151. return;
  152. }
  153. env->CallVoidMethod(ref->frameListener, VirtualNetworkFrameListener_onVirtualNetworkFrame_method, (jlong)nwid, (jlong)sourceMac, (jlong)destMac, (jlong)etherType, (jlong)vlanid, dataArray);
  154. }
  155. void EventCallback(ZT_Node *node,
  156. void *userData,
  157. void *threadData,
  158. enum ZT_Event event,
  159. const void *data) {
  160. LOGV("EventCallback");
  161. JniRef *ref = (JniRef *) userData;
  162. if (ref->node != node && event != ZT_EVENT_UP) {
  163. LOGE("Nodes not equal. ref->node %p, node %p. Event: %d", ref->node, node, event);
  164. return;
  165. }
  166. JNIEnv *env = NULL;
  167. ref->jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
  168. if (ref->eventListener == NULL) {
  169. LOGE("eventListener is NULL");
  170. return;
  171. }
  172. jobject eventObject = createEvent(env, event);
  173. if (env->ExceptionCheck() || eventObject == NULL) {
  174. return;
  175. }
  176. switch (event) {
  177. case ZT_EVENT_UP: {
  178. LOGD("Event Up");
  179. env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
  180. break;
  181. }
  182. case ZT_EVENT_OFFLINE: {
  183. LOGD("Event Offline");
  184. env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
  185. break;
  186. }
  187. case ZT_EVENT_ONLINE: {
  188. LOGD("Event Online");
  189. env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
  190. break;
  191. }
  192. case ZT_EVENT_DOWN: {
  193. LOGD("Event Down");
  194. env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
  195. break;
  196. }
  197. case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: {
  198. LOGV("Identity Collision");
  199. // call onEvent()
  200. env->CallVoidMethod(ref->eventListener, EventListener_onEvent_method, eventObject);
  201. }
  202. break;
  203. case ZT_EVENT_TRACE: {
  204. LOGV("Trace Event");
  205. // call onTrace()
  206. if (data != NULL) {
  207. const char *message = (const char *) data;
  208. jstring messageStr = env->NewStringUTF(message);
  209. env->CallVoidMethod(ref->eventListener, EventListener_onTrace_method, messageStr);
  210. }
  211. }
  212. break;
  213. case ZT_EVENT_USER_MESSAGE:
  214. case ZT_EVENT_REMOTE_TRACE:
  215. default:
  216. break;
  217. }
  218. }
  219. void StatePutFunction(
  220. ZT_Node *node,
  221. void *userData,
  222. void *threadData,
  223. enum ZT_StateObjectType type,
  224. const uint64_t id[2],
  225. const void *buffer,
  226. int bufferLength) {
  227. char p[4096] = {0};
  228. bool secure = false;
  229. switch (type) {
  230. case ZT_STATE_OBJECT_IDENTITY_PUBLIC:
  231. snprintf(p, sizeof(p), "identity.public");
  232. break;
  233. case ZT_STATE_OBJECT_IDENTITY_SECRET:
  234. snprintf(p, sizeof(p), "identity.secret");
  235. secure = true;
  236. break;
  237. case ZT_STATE_OBJECT_PLANET:
  238. snprintf(p, sizeof(p), "planet");
  239. break;
  240. case ZT_STATE_OBJECT_MOON:
  241. snprintf(p, sizeof(p), "moons.d/%.16llx.moon", (unsigned long long)id[0]);
  242. break;
  243. case ZT_STATE_OBJECT_NETWORK_CONFIG:
  244. snprintf(p, sizeof(p), "networks.d/%.16llx.conf", (unsigned long long)id[0]);
  245. break;
  246. case ZT_STATE_OBJECT_PEER:
  247. snprintf(p, sizeof(p), "peers.d/%.10llx", (unsigned long long)id[0]);
  248. break;
  249. default:
  250. return;
  251. }
  252. if (strlen(p) < 1) {
  253. return;
  254. }
  255. JniRef *ref = (JniRef*)userData;
  256. JNIEnv *env = NULL;
  257. ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
  258. if (ref->dataStorePutListener == NULL) {
  259. LOGE("dataStorePutListener is NULL");
  260. return;
  261. }
  262. jstring nameStr = env->NewStringUTF(p);
  263. if (bufferLength >= 0) {
  264. LOGD("JNI: Write file: %s", p);
  265. // set operation
  266. jbyteArray bufferObj = env->NewByteArray(bufferLength);
  267. if(env->ExceptionCheck() || bufferObj == NULL)
  268. {
  269. LOGE("Error creating byte array buffer!");
  270. return;
  271. }
  272. env->SetByteArrayRegion(bufferObj, 0, bufferLength, (jbyte*)buffer);
  273. env->CallIntMethod(ref->dataStorePutListener,
  274. DataStorePutListener_onDataStorePut_method,
  275. nameStr, bufferObj, secure);
  276. } else {
  277. LOGD("JNI: Delete file: %s", p);
  278. env->CallIntMethod(ref->dataStorePutListener, DataStorePutListener_onDelete_method, nameStr);
  279. }
  280. }
  281. int StateGetFunction(
  282. ZT_Node *node,
  283. void *userData,
  284. void *threadData,
  285. ZT_StateObjectType type,
  286. const uint64_t id[2],
  287. void *buffer,
  288. unsigned int bufferLength) {
  289. char p[4096] = {0};
  290. switch (type) {
  291. case ZT_STATE_OBJECT_IDENTITY_PUBLIC:
  292. snprintf(p, sizeof(p), "identity.public");
  293. break;
  294. case ZT_STATE_OBJECT_IDENTITY_SECRET:
  295. snprintf(p, sizeof(p), "identity.secret");
  296. break;
  297. case ZT_STATE_OBJECT_PLANET:
  298. snprintf(p, sizeof(p), "planet");
  299. break;
  300. case ZT_STATE_OBJECT_MOON:
  301. snprintf(p, sizeof(p), "moons.d/%.16llx.moon", (unsigned long long)id[0]);
  302. break;
  303. case ZT_STATE_OBJECT_NETWORK_CONFIG:
  304. snprintf(p, sizeof(p), "networks.d/%.16llx.conf", (unsigned long long)id[0]);
  305. break;
  306. case ZT_STATE_OBJECT_PEER:
  307. snprintf(p, sizeof(p), "peers.d/%.10llx", (unsigned long long)id[0]);
  308. break;
  309. default:
  310. return -100;
  311. }
  312. if (strlen(p) < 1) {
  313. return -101;
  314. }
  315. JniRef *ref = (JniRef*)userData;
  316. JNIEnv *env = NULL;
  317. ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
  318. if (ref->dataStoreGetListener == NULL) {
  319. LOGE("dataStoreGetListener is NULL");
  320. return -102;
  321. }
  322. jstring nameStr = env->NewStringUTF(p);
  323. if(nameStr == NULL)
  324. {
  325. LOGE("Error creating name string object");
  326. return -103; // out of memory
  327. }
  328. jbyteArray bufferObj = env->NewByteArray(bufferLength);
  329. if(bufferObj == NULL)
  330. {
  331. LOGE("Error creating byte[] buffer of size: %u", bufferLength);
  332. return -104;
  333. }
  334. LOGV("Calling onDataStoreGet(%s, %p)", p, buffer);
  335. int retval = (int)env->CallLongMethod(
  336. ref->dataStoreGetListener,
  337. DataStoreGetListener_onDataStoreGet_method,
  338. nameStr,
  339. bufferObj);
  340. LOGV("onDataStoreGet returned %d", retval);
  341. if(retval > 0)
  342. {
  343. void *data = env->GetPrimitiveArrayCritical(bufferObj, NULL);
  344. memcpy(buffer, data, retval);
  345. env->ReleasePrimitiveArrayCritical(bufferObj, data, 0);
  346. }
  347. return retval;
  348. }
  349. int WirePacketSendFunction(ZT_Node *node,
  350. void *userData,
  351. void *threadData,
  352. int64_t localSocket,
  353. const struct sockaddr_storage *remoteAddress,
  354. const void *buffer,
  355. unsigned int bufferSize,
  356. unsigned int ttl)
  357. {
  358. LOGV("WirePacketSendFunction(%lld, %p, %p, %d)", (long long)localSocket, remoteAddress, buffer, bufferSize);
  359. JniRef *ref = (JniRef*)userData;
  360. assert(ref->node == node);
  361. JNIEnv *env = NULL;
  362. ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
  363. if (ref->packetSender == NULL) {
  364. LOGE("packetSender is NULL");
  365. return -100;
  366. }
  367. jobject remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
  368. jbyteArray bufferObj = env->NewByteArray(bufferSize);
  369. env->SetByteArrayRegion(bufferObj, 0, bufferSize, (jbyte*)buffer);
  370. int retval = env->CallIntMethod(ref->packetSender, PacketSender_onSendPacketRequested_method, localSocket, remoteAddressObj, bufferObj);
  371. LOGV("JNI Packet Sender returned: %d", retval);
  372. return retval;
  373. }
  374. int PathCheckFunction(ZT_Node *node,
  375. void *userPtr,
  376. void *threadPtr,
  377. uint64_t address,
  378. int64_t localSocket,
  379. const struct sockaddr_storage *remoteAddress)
  380. {
  381. JniRef *ref = (JniRef*)userPtr;
  382. assert(ref->node == node);
  383. if(ref->pathChecker == NULL) {
  384. return true;
  385. }
  386. JNIEnv *env = NULL;
  387. ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
  388. //
  389. // was:
  390. // struct sockaddr_storage nullAddress = {0};
  391. //
  392. // but was getting this warning:
  393. // warning: suggest braces around initialization of subobject
  394. //
  395. // when building ZeroTierOne
  396. //
  397. struct sockaddr_storage nullAddress;
  398. //
  399. // It is possible to assume knowledge about internals of sockaddr_storage and construct
  400. // correct 0-initializer, but it is simpler to just treat sockaddr_storage as opaque and
  401. // use memset here to fill with 0
  402. //
  403. // This is also done in InetAddress.hpp for InetAddress
  404. //
  405. memset(&nullAddress, 0, sizeof(sockaddr_storage));
  406. jobject remoteAddressObj = NULL;
  407. if(memcmp(remoteAddress, &nullAddress, sizeof(sockaddr_storage)) != 0)
  408. {
  409. remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
  410. }
  411. return env->CallBooleanMethod(ref->pathChecker, PathChecker_onPathCheck_method, address, localSocket, remoteAddressObj);
  412. }
  413. int PathLookupFunction(ZT_Node *node,
  414. void *userPtr,
  415. void *threadPtr,
  416. uint64_t address,
  417. int ss_family,
  418. struct sockaddr_storage *result)
  419. {
  420. JniRef *ref = (JniRef*)userPtr;
  421. assert(ref->node == node);
  422. if(ref->pathChecker == NULL) {
  423. return false;
  424. }
  425. JNIEnv *env = NULL;
  426. ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
  427. jobject sockAddressObject = env->CallObjectMethod(ref->pathChecker, PathChecker_onPathLookup_method, address, ss_family);
  428. if(sockAddressObject == NULL)
  429. {
  430. LOGE("Unable to call onPathLookup implementation");
  431. return false;
  432. }
  433. jint port = env->CallIntMethod(sockAddressObject, InetSocketAddress_getPort_method);
  434. jobject addressObject = env->CallObjectMethod(sockAddressObject, InetSocketAddress_getAddress_method);
  435. jbyteArray addressBytes = (jbyteArray)env->CallObjectMethod(addressObject, InetAddress_getAddress_method);
  436. if(addressBytes == NULL)
  437. {
  438. LOGE("Unable to call InetAddress.getBytes()");
  439. return false;
  440. }
  441. int addressSize = env->GetArrayLength(addressBytes);
  442. if(addressSize == 4)
  443. {
  444. // IPV4
  445. sockaddr_in *addr = (sockaddr_in*)result;
  446. addr->sin_family = AF_INET;
  447. addr->sin_port = htons(port);
  448. void *data = env->GetPrimitiveArrayCritical(addressBytes, NULL);
  449. memcpy(&addr->sin_addr, data, 4);
  450. env->ReleasePrimitiveArrayCritical(addressBytes, data, 0);
  451. }
  452. else if (addressSize == 16)
  453. {
  454. // IPV6
  455. sockaddr_in6 *addr = (sockaddr_in6*)result;
  456. addr->sin6_family = AF_INET6;
  457. addr->sin6_port = htons(port);
  458. void *data = env->GetPrimitiveArrayCritical(addressBytes, NULL);
  459. memcpy(&addr->sin6_addr, data, 16);
  460. env->ReleasePrimitiveArrayCritical(addressBytes, data, 0);
  461. }
  462. else
  463. {
  464. return false;
  465. }
  466. return true;
  467. }
  468. typedef std::map<int64_t, JniRef*> NodeMap;
  469. static NodeMap nodeMap;
  470. ZeroTier::Mutex nodeMapMutex;
  471. ZT_Node* findNode(int64_t nodeId)
  472. {
  473. ZeroTier::Mutex::Lock lock(nodeMapMutex);
  474. NodeMap::iterator found = nodeMap.find(nodeId);
  475. if(found != nodeMap.end())
  476. {
  477. JniRef *ref = found->second;
  478. return ref->node;
  479. }
  480. return NULL;
  481. }
  482. }
  483. #ifdef __cplusplus
  484. extern "C" {
  485. #endif
  486. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
  487. {
  488. setupJNICache(vm);
  489. return JNI_VERSION_1_6;
  490. }
  491. JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
  492. {
  493. teardownJNICache(vm);
  494. }
  495. /*
  496. * Class: com_zerotier_sdk_Node
  497. * Method: node_init
  498. * Signature: (J)Lcom/zerotier/sdk/ResultCode;
  499. */
  500. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
  501. JNIEnv *env, jobject obj, jlong now)
  502. {
  503. LOGV("Creating ZT_Node struct");
  504. jobject resultObject = ResultCode_RESULT_OK_enum;
  505. ZT_Node *node;
  506. JniRef *ref = new JniRef;
  507. ref->id = (int64_t)now;
  508. env->GetJavaVM(&ref->jvm);
  509. jobject dataStoreGetListener = env->GetObjectField(obj, Node_getListener_field);
  510. if(dataStoreGetListener == NULL)
  511. {
  512. return NULL;
  513. }
  514. ref->dataStoreGetListener = env->NewGlobalRef(dataStoreGetListener);
  515. jobject dataStorePutListener = env->GetObjectField(obj, Node_putListener_field);
  516. if(dataStorePutListener == NULL)
  517. {
  518. return NULL;
  519. }
  520. ref->dataStorePutListener = env->NewGlobalRef(dataStorePutListener);
  521. jobject packetSender = env->GetObjectField(obj, Node_sender_field);
  522. if(packetSender == NULL)
  523. {
  524. return NULL;
  525. }
  526. ref->packetSender = env->NewGlobalRef(packetSender);
  527. jobject frameListener = env->GetObjectField(obj, Node_frameListener_field);
  528. if(frameListener == NULL)
  529. {
  530. return NULL;
  531. }
  532. ref->frameListener = env->NewGlobalRef(frameListener);
  533. jobject configListener = env->GetObjectField(obj, Node_configListener_field);
  534. if(configListener == NULL)
  535. {
  536. return NULL;
  537. }
  538. ref->configListener = env->NewGlobalRef(configListener);
  539. jobject eventListener = env->GetObjectField(obj, Node_eventListener_field);
  540. if(eventListener == NULL)
  541. {
  542. return NULL;
  543. }
  544. ref->eventListener = env->NewGlobalRef(eventListener);
  545. jobject pathChecker = env->GetObjectField(obj, Node_pathChecker_field);
  546. if(pathChecker != NULL)
  547. {
  548. ref->pathChecker = env->NewGlobalRef(pathChecker);
  549. }
  550. ref->callbacks->stateGetFunction = &StateGetFunction;
  551. ref->callbacks->statePutFunction = &StatePutFunction;
  552. ref->callbacks->wirePacketSendFunction = &WirePacketSendFunction;
  553. ref->callbacks->virtualNetworkFrameFunction = &VirtualNetworkFrameFunctionCallback;
  554. ref->callbacks->virtualNetworkConfigFunction = &VirtualNetworkConfigFunctionCallback;
  555. ref->callbacks->eventCallback = &EventCallback;
  556. ref->callbacks->pathCheckFunction = &PathCheckFunction;
  557. ref->callbacks->pathLookupFunction = &PathLookupFunction;
  558. ZT_ResultCode rc = ZT_Node_new(
  559. &node,
  560. ref,
  561. NULL,
  562. ref->callbacks,
  563. (int64_t)now);
  564. if(rc != ZT_RESULT_OK)
  565. {
  566. LOGE("Error creating Node: %d", rc);
  567. resultObject = createResultObject(env, rc);
  568. if (env->ExceptionCheck() || resultObject == NULL) {
  569. return NULL;
  570. }
  571. if(node)
  572. {
  573. ZT_Node_delete(node);
  574. node = NULL;
  575. }
  576. delete ref;
  577. ref = NULL;
  578. return resultObject;
  579. }
  580. ZeroTier::Mutex::Lock lock(nodeMapMutex);
  581. ref->node = node;
  582. nodeMap.insert(std::make_pair(ref->id, ref));
  583. return resultObject;
  584. }
  585. /*
  586. * Class: com_zerotier_sdk_Node
  587. * Method: node_delete
  588. * Signature: (J)V
  589. */
  590. JNIEXPORT void JNICALL Java_com_zerotier_sdk_Node_node_1delete(
  591. JNIEnv *env, jobject obj, jlong id)
  592. {
  593. LOGV("Destroying ZT_Node struct");
  594. int64_t nodeId = (int64_t)id;
  595. NodeMap::iterator found;
  596. {
  597. ZeroTier::Mutex::Lock lock(nodeMapMutex);
  598. found = nodeMap.find(nodeId);
  599. }
  600. if(found != nodeMap.end())
  601. {
  602. JniRef *ref = found->second;
  603. nodeMap.erase(found);
  604. ZT_Node_delete(ref->node);
  605. delete ref;
  606. ref = NULL;
  607. }
  608. else
  609. {
  610. LOGE("Attempted to delete a node that doesn't exist!");
  611. }
  612. }
  613. /*
  614. * Class: com_zerotier_sdk_Node
  615. * Method: processVirtualNetworkFrame
  616. * Signature: (JJJJJII[B[J)Lcom/zerotier/sdk/ResultCode;
  617. */
  618. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame(
  619. JNIEnv *env, jobject obj,
  620. jlong id,
  621. jlong in_now,
  622. jlong in_nwid,
  623. jlong in_sourceMac,
  624. jlong in_destMac,
  625. jint in_etherType,
  626. jint in_vlanId,
  627. jbyteArray in_frameData,
  628. jlongArray out_nextBackgroundTaskDeadline)
  629. {
  630. int64_t nodeId = (int64_t) id;
  631. ZT_Node *node = findNode(nodeId);
  632. if(node == NULL)
  633. {
  634. // cannot find valid node. We should never get here.
  635. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  636. }
  637. unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline);
  638. if(nbtd_len < 1)
  639. {
  640. // array for next background task length has 0 elements!
  641. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  642. }
  643. int64_t now = (int64_t)in_now;
  644. uint64_t nwid = (uint64_t)in_nwid;
  645. uint64_t sourceMac = (uint64_t)in_sourceMac;
  646. uint64_t destMac = (uint64_t)in_destMac;
  647. unsigned int etherType = (unsigned int)in_etherType;
  648. unsigned int vlanId = (unsigned int)in_vlanId;
  649. unsigned int frameLength = env->GetArrayLength(in_frameData);
  650. void *frameData = env->GetPrimitiveArrayCritical(in_frameData, NULL);
  651. void *localData = malloc(frameLength);
  652. memcpy(localData, frameData, frameLength);
  653. env->ReleasePrimitiveArrayCritical(in_frameData, frameData, 0);
  654. int64_t nextBackgroundTaskDeadline = 0;
  655. ZT_ResultCode rc = ZT_Node_processVirtualNetworkFrame(
  656. node,
  657. NULL,
  658. now,
  659. nwid,
  660. sourceMac,
  661. destMac,
  662. etherType,
  663. vlanId,
  664. (const void*)localData,
  665. frameLength,
  666. &nextBackgroundTaskDeadline);
  667. free(localData);
  668. jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
  669. outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
  670. env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0);
  671. return createResultObject(env, rc);
  672. }
  673. /*
  674. * Class: com_zerotier_sdk_Node
  675. * Method: processWirePacket
  676. * Signature: (JJJLjava/net/InetSocketAddress;[B[J)Lcom/zerotier/sdk/ResultCode;
  677. */
  678. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
  679. JNIEnv *env, jobject obj,
  680. jlong id,
  681. jlong in_now,
  682. jlong in_localSocket,
  683. jobject in_remoteAddress,
  684. jbyteArray in_packetData,
  685. jlongArray out_nextBackgroundTaskDeadline)
  686. {
  687. int64_t nodeId = (int64_t) id;
  688. ZT_Node *node = findNode(nodeId);
  689. if(node == NULL)
  690. {
  691. // cannot find valid node. We should never get here.
  692. LOGE("Couldn't find a valid node!");
  693. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  694. }
  695. unsigned int nbtd_len = (unsigned int)env->GetArrayLength(out_nextBackgroundTaskDeadline);
  696. if(nbtd_len < 1)
  697. {
  698. LOGE("nbtd_len < 1");
  699. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  700. }
  701. int64_t now = (int64_t)in_now;
  702. jobject remoteAddrObject = env->CallObjectMethod(in_remoteAddress, InetSocketAddress_getAddress_method);
  703. if(remoteAddrObject == NULL)
  704. {
  705. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  706. }
  707. // call InetSocketAddress.getPort()
  708. int remotePort = env->CallIntMethod(in_remoteAddress, InetSocketAddress_getPort_method);
  709. if(env->ExceptionCheck())
  710. {
  711. LOGE("Exception calling InetSocketAddress.getPort()");
  712. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  713. }
  714. // Call InetAddress.getAddress()
  715. jbyteArray remoteAddressArray = (jbyteArray)env->CallObjectMethod(remoteAddrObject, InetAddress_getAddress_method);
  716. if(remoteAddressArray == NULL)
  717. {
  718. LOGE("Unable to call getAddress()");
  719. // unable to call getAddress()
  720. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  721. }
  722. unsigned int addrSize = env->GetArrayLength(remoteAddressArray);
  723. // get the address bytes
  724. jbyte *addr = (jbyte*)env->GetPrimitiveArrayCritical(remoteAddressArray, NULL);
  725. sockaddr_storage remoteAddress = {};
  726. if(addrSize == 16)
  727. {
  728. // IPV6 address
  729. sockaddr_in6 ipv6 = {};
  730. ipv6.sin6_family = AF_INET6;
  731. ipv6.sin6_port = htons(remotePort);
  732. memcpy(ipv6.sin6_addr.s6_addr, addr, 16);
  733. memcpy(&remoteAddress, &ipv6, sizeof(sockaddr_in6));
  734. }
  735. else if(addrSize == 4)
  736. {
  737. // IPV4 address
  738. sockaddr_in ipv4 = {};
  739. ipv4.sin_family = AF_INET;
  740. ipv4.sin_port = htons(remotePort);
  741. memcpy(&ipv4.sin_addr, addr, 4);
  742. memcpy(&remoteAddress, &ipv4, sizeof(sockaddr_in));
  743. }
  744. else
  745. {
  746. LOGE("Unknown IP version");
  747. // unknown address type
  748. env->ReleasePrimitiveArrayCritical(remoteAddressArray, addr, 0);
  749. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  750. }
  751. env->ReleasePrimitiveArrayCritical(remoteAddressArray, addr, 0);
  752. unsigned int packetLength = (unsigned int)env->GetArrayLength(in_packetData);
  753. if(packetLength == 0)
  754. {
  755. LOGE("Empty packet?!?");
  756. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  757. }
  758. void *packetData = env->GetPrimitiveArrayCritical(in_packetData, NULL);
  759. void *localData = malloc(packetLength);
  760. memcpy(localData, packetData, packetLength);
  761. env->ReleasePrimitiveArrayCritical(in_packetData, packetData, 0);
  762. int64_t nextBackgroundTaskDeadline = 0;
  763. ZT_ResultCode rc = ZT_Node_processWirePacket(
  764. node,
  765. NULL,
  766. now,
  767. in_localSocket,
  768. &remoteAddress,
  769. localData,
  770. packetLength,
  771. &nextBackgroundTaskDeadline);
  772. if(rc != ZT_RESULT_OK)
  773. {
  774. LOGE("ZT_Node_processWirePacket returned: %d", rc);
  775. }
  776. free(localData);
  777. jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
  778. outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
  779. env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0);
  780. return createResultObject(env, rc);
  781. }
  782. /*
  783. * Class: com_zerotier_sdk_Node
  784. * Method: processBackgroundTasks
  785. * Signature: (JJ[J)Lcom/zerotier/sdk/ResultCode;
  786. */
  787. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processBackgroundTasks(
  788. JNIEnv *env, jobject obj,
  789. jlong id,
  790. jlong in_now,
  791. jlongArray out_nextBackgroundTaskDeadline)
  792. {
  793. int64_t nodeId = (int64_t) id;
  794. ZT_Node *node = findNode(nodeId);
  795. if(node == NULL)
  796. {
  797. // cannot find valid node. We should never get here.
  798. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  799. }
  800. unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline);
  801. if(nbtd_len < 1)
  802. {
  803. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  804. }
  805. int64_t now = (int64_t)in_now;
  806. int64_t nextBackgroundTaskDeadline = 0;
  807. ZT_ResultCode rc = ZT_Node_processBackgroundTasks(node, NULL, now, &nextBackgroundTaskDeadline);
  808. jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
  809. outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
  810. env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0);
  811. return createResultObject(env, rc);
  812. }
  813. /*
  814. * Class: com_zerotier_sdk_Node
  815. * Method: join
  816. * Signature: (JJ)Lcom/zerotier/sdk/ResultCode;
  817. */
  818. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_join(
  819. JNIEnv *env, jobject obj, jlong id, jlong in_nwid)
  820. {
  821. int64_t nodeId = (int64_t) id;
  822. ZT_Node *node = findNode(nodeId);
  823. if(node == NULL)
  824. {
  825. // cannot find valid node. We should never get here.
  826. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  827. }
  828. uint64_t nwid = (uint64_t)in_nwid;
  829. ZT_ResultCode rc = ZT_Node_join(node, nwid, NULL, NULL);
  830. return createResultObject(env, rc);
  831. }
  832. /*
  833. * Class: com_zerotier_sdk_Node
  834. * Method: leave
  835. * Signature: (JJ)Lcom/zerotier/sdk/ResultCode;
  836. */
  837. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_leave(
  838. JNIEnv *env, jobject obj, jlong id, jlong in_nwid)
  839. {
  840. int64_t nodeId = (int64_t) id;
  841. ZT_Node *node = findNode(nodeId);
  842. if(node == NULL)
  843. {
  844. // cannot find valid node. We should never get here.
  845. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  846. }
  847. uint64_t nwid = (uint64_t)in_nwid;
  848. ZT_ResultCode rc = ZT_Node_leave(node, nwid, NULL, NULL);
  849. return createResultObject(env, rc);
  850. }
  851. /*
  852. * Class: com_zerotier_sdk_Node
  853. * Method: multicastSubscribe
  854. * Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode;
  855. */
  856. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastSubscribe(
  857. JNIEnv *env, jobject obj,
  858. jlong id,
  859. jlong in_nwid,
  860. jlong in_multicastGroup,
  861. jlong in_multicastAdi)
  862. {
  863. int64_t nodeId = (int64_t) id;
  864. ZT_Node *node = findNode(nodeId);
  865. if(node == NULL)
  866. {
  867. // cannot find valid node. We should never get here.
  868. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  869. }
  870. uint64_t nwid = (uint64_t)in_nwid;
  871. uint64_t multicastGroup = (uint64_t)in_multicastGroup;
  872. unsigned long multicastAdi = (unsigned long)in_multicastAdi;
  873. ZT_ResultCode rc = ZT_Node_multicastSubscribe(
  874. node, NULL, nwid, multicastGroup, multicastAdi);
  875. return createResultObject(env, rc);
  876. }
  877. /*
  878. * Class: com_zerotier_sdk_Node
  879. * Method: multicastUnsubscribe
  880. * Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode;
  881. */
  882. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastUnsubscribe(
  883. JNIEnv *env, jobject obj,
  884. jlong id,
  885. jlong in_nwid,
  886. jlong in_multicastGroup,
  887. jlong in_multicastAdi)
  888. {
  889. int64_t nodeId = (int64_t) id;
  890. ZT_Node *node = findNode(nodeId);
  891. if(node == NULL)
  892. {
  893. // cannot find valid node. We should never get here.
  894. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  895. }
  896. uint64_t nwid = (uint64_t)in_nwid;
  897. uint64_t multicastGroup = (uint64_t)in_multicastGroup;
  898. unsigned long multicastAdi = (unsigned long)in_multicastAdi;
  899. ZT_ResultCode rc = ZT_Node_multicastUnsubscribe(
  900. node, nwid, multicastGroup, multicastAdi);
  901. return createResultObject(env, rc);
  902. }
  903. /*
  904. * Class: com_zerotier_sdk_Node
  905. * Method: orbit
  906. * Signature: (JJJ)Lcom/zerotier/sdk/ResultCode;
  907. */
  908. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_orbit(
  909. JNIEnv *env, jobject obj,
  910. jlong id,
  911. jlong in_moonWorldId,
  912. jlong in_moonSeed)
  913. {
  914. int64_t nodeId = (int64_t)id;
  915. ZT_Node *node = findNode(nodeId);
  916. if(node == NULL)
  917. {
  918. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  919. }
  920. uint64_t moonWorldId = (uint64_t)in_moonWorldId;
  921. uint64_t moonSeed = (uint64_t)in_moonSeed;
  922. ZT_ResultCode rc = ZT_Node_orbit(node, NULL, moonWorldId, moonSeed);
  923. return createResultObject(env, rc);
  924. }
  925. /*
  926. * Class: com_zerotier_sdk_Node
  927. * Method: deorbit
  928. * Signature: (JJ)L/com/zerotier/sdk/ResultCode;
  929. */
  930. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_deorbit(
  931. JNIEnv *env, jobject obj,
  932. jlong id,
  933. jlong in_moonWorldId)
  934. {
  935. int64_t nodeId = (int64_t)id;
  936. ZT_Node *node = findNode(nodeId);
  937. if(node == NULL)
  938. {
  939. return ResultCode_RESULT_FATAL_ERROR_INTERNAL_enum;
  940. }
  941. uint64_t moonWorldId = (uint64_t)in_moonWorldId;
  942. ZT_ResultCode rc = ZT_Node_deorbit(node, NULL, moonWorldId);
  943. return createResultObject(env, rc);
  944. }
  945. /*
  946. * Class: com_zerotier_sdk_Node
  947. * Method: address
  948. * Signature: (J)J
  949. */
  950. JNIEXPORT jlong JNICALL Java_com_zerotier_sdk_Node_address(
  951. JNIEnv *env , jobject obj, jlong id)
  952. {
  953. int64_t nodeId = (int64_t) id;
  954. ZT_Node *node = findNode(nodeId);
  955. if(node == NULL)
  956. {
  957. // cannot find valid node. We should never get here.
  958. return 0;
  959. }
  960. uint64_t address = ZT_Node_address(node);
  961. return (jlong)address;
  962. }
  963. /*
  964. * Class: com_zerotier_sdk_Node
  965. * Method: status
  966. * Signature: (J)Lcom/zerotier/sdk/NodeStatus;
  967. */
  968. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_status
  969. (JNIEnv *env, jobject obj, jlong id)
  970. {
  971. int64_t nodeId = (int64_t) id;
  972. ZT_Node *node = findNode(nodeId);
  973. ZT_NodeStatus nodeStatus;
  974. ZT_Node_status(node, &nodeStatus);
  975. return newNodeStatus(env, nodeStatus);
  976. }
  977. /*
  978. * Class: com_zerotier_sdk_Node
  979. * Method: networkConfig
  980. * Signature: (JJ)Lcom/zerotier/sdk/VirtualNetworkConfig;
  981. */
  982. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_networkConfig(
  983. JNIEnv *env, jobject obj, jlong id, jlong nwid)
  984. {
  985. int64_t nodeId = (int64_t) id;
  986. ZT_Node *node = findNode(nodeId);
  987. if(node == NULL)
  988. {
  989. // cannot find valid node. We should never get here.
  990. return 0;
  991. }
  992. ZT_VirtualNetworkConfig *vnetConfig = ZT_Node_networkConfig(node, nwid);
  993. jobject vnetConfigObject = newNetworkConfig(env, *vnetConfig);
  994. ZT_Node_freeQueryResult(node, vnetConfig);
  995. return vnetConfigObject;
  996. }
  997. /*
  998. * Class: com_zerotier_sdk_Node
  999. * Method: version
  1000. * Signature: ()Lcom/zerotier/sdk/Version;
  1001. */
  1002. JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_version(
  1003. JNIEnv *env, jobject obj)
  1004. {
  1005. int major = 0;
  1006. int minor = 0;
  1007. int revision = 0;
  1008. ZT_version(&major, &minor, &revision);
  1009. return newVersion(env, major, minor, revision);
  1010. }
  1011. /*
  1012. * Class: com_zerotier_sdk_Node
  1013. * Method: peers
  1014. * Signature: (J)[Lcom/zerotier/sdk/Peer;
  1015. */
  1016. JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers(
  1017. JNIEnv *env, jobject obj, jlong id)
  1018. {
  1019. int64_t nodeId = (int64_t) id;
  1020. ZT_Node *node = findNode(nodeId);
  1021. if(node == NULL)
  1022. {
  1023. // cannot find valid node. We should never get here.
  1024. return 0;
  1025. }
  1026. ZT_PeerList *peerList = ZT_Node_peers(node);
  1027. if(peerList == NULL)
  1028. {
  1029. LOGE("ZT_Node_peers returned NULL");
  1030. return NULL;
  1031. }
  1032. jobjectArray peerArrayObj = env->NewObjectArray(
  1033. peerList->peerCount, Peer_class, NULL);
  1034. if(env->ExceptionCheck() || peerArrayObj == NULL)
  1035. {
  1036. LOGE("Error creating Peer[] array");
  1037. ZT_Node_freeQueryResult(node, peerList);
  1038. return NULL;
  1039. }
  1040. for(unsigned int i = 0; i < peerList->peerCount; ++i)
  1041. {
  1042. jobject peerObj = newPeer(env, peerList->peers[i]);
  1043. env->SetObjectArrayElement(peerArrayObj, i, peerObj);
  1044. if(env->ExceptionCheck())
  1045. {
  1046. LOGE("Error assigning Peer object to array");
  1047. break;
  1048. }
  1049. env->DeleteLocalRef(peerObj);
  1050. }
  1051. ZT_Node_freeQueryResult(node, peerList);
  1052. peerList = NULL;
  1053. return peerArrayObj;
  1054. }
  1055. /*
  1056. * Class: com_zerotier_sdk_Node
  1057. * Method: networks
  1058. * Signature: (J)[Lcom/zerotier/sdk/VirtualNetworkConfig;
  1059. */
  1060. JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networks(
  1061. JNIEnv *env, jobject obj, jlong id)
  1062. {
  1063. int64_t nodeId = (int64_t) id;
  1064. ZT_Node *node = findNode(nodeId);
  1065. if(node == NULL)
  1066. {
  1067. // cannot find valid node. We should never get here.
  1068. return 0;
  1069. }
  1070. ZT_VirtualNetworkList *networkList = ZT_Node_networks(node);
  1071. if(networkList == NULL)
  1072. {
  1073. return NULL;
  1074. }
  1075. jobjectArray networkListObject = env->NewObjectArray(
  1076. networkList->networkCount, VirtualNetworkConfig_class, NULL);
  1077. if(env->ExceptionCheck() || networkListObject == NULL)
  1078. {
  1079. LOGE("Error creating VirtualNetworkConfig[] array");
  1080. ZT_Node_freeQueryResult(node, networkList);
  1081. return NULL;
  1082. }
  1083. for(unsigned int i = 0; i < networkList->networkCount; ++i)
  1084. {
  1085. jobject networkObject = newNetworkConfig(env, networkList->networks[i]);
  1086. env->SetObjectArrayElement(networkListObject, i, networkObject);
  1087. if(env->ExceptionCheck())
  1088. {
  1089. LOGE("Error assigning VirtualNetworkConfig object to array");
  1090. break;
  1091. }
  1092. env->DeleteLocalRef(networkObject);
  1093. }
  1094. ZT_Node_freeQueryResult(node, networkList);
  1095. return networkListObject;
  1096. }
  1097. #ifdef __cplusplus
  1098. } // extern "C"
  1099. #endif