diff --git a/java/jni/ZT_jniutils.cpp b/java/jni/ZT_jniutils.cpp index d6faafeb2..3f90c6f79 100644 --- a/java/jni/ZT_jniutils.cpp +++ b/java/jni/ZT_jniutils.cpp @@ -107,14 +107,14 @@ jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr) case AF_INET6: { sockaddr_in6 *ipv6 = (sockaddr_in6*)&addr; - jbyteArray buff = env->NewByteArray(16); - if(buff == NULL) + const unsigned char *bytes = reinterpret_cast(&ipv6->sin6_addr.s6_addr); + + jbyteArray buff = newByteArray(env, bytes, 16); + if(env->ExceptionCheck() || buff == NULL) { - LOGE("Error creating IPV6 byte array"); return NULL; } - env->SetByteArrayRegion(buff, 0, 16, (jbyte*)ipv6->sin6_addr.s6_addr); inetAddressObj = env->CallStaticObjectMethod( InetAddress_class, InetAddress_getByAddress_method, buff); } @@ -122,14 +122,13 @@ jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr) case AF_INET: { sockaddr_in *ipv4 = (sockaddr_in*)&addr; - jbyteArray buff = env->NewByteArray(4); - if(buff == NULL) + const unsigned char *bytes = reinterpret_cast(&ipv4->sin_addr.s_addr); + jbyteArray buff = newByteArray(env, bytes, 4); + if(env->ExceptionCheck() || buff == NULL) { - LOGE("Error creating IPV4 byte array"); return NULL; } - env->SetByteArrayRegion(buff, 0, 4, (jbyte*)&ipv4->sin_addr); inetAddressObj = env->CallStaticObjectMethod( InetAddress_class, InetAddress_getByAddress_method, buff); } @@ -241,26 +240,7 @@ jobject newPeer(JNIEnv *env, const ZT_Peer &peer) env->SetIntField(peerObject, Peer_latency_field, peer.latency); env->SetObjectField(peerObject, Peer_role_field, createPeerRole(env, peer.role)); - jobjectArray arrayObject = env->NewObjectArray( - peer.pathCount, PeerPhysicalPath_class, NULL); - if(env->ExceptionCheck() || arrayObject == NULL) - { - LOGE("Error creating PeerPhysicalPath[] array"); - return NULL; - } - - for(unsigned int i = 0; i < peer.pathCount; ++i) - { - jobject path = newPeerPhysicalPath(env, peer.paths[i]); - - env->SetObjectArrayElement(arrayObject, i, path); - if(env->ExceptionCheck()) { - LOGE("exception assigning PeerPhysicalPath to array"); - break; - } - - env->DeleteLocalRef(path); - } + jobjectArray arrayObject = newPeerPhysicalPathArray(env, peer.paths, peer.pathCount); env->SetObjectField(peerObject, Peer_paths_field, arrayObject); @@ -305,49 +285,11 @@ jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &vnetConfig) env->SetBooleanField(vnetConfigObj, VirtualNetworkConfig_broadcastEnabled_field, vnetConfig.broadcastEnabled); env->SetIntField(vnetConfigObj, VirtualNetworkConfig_portError_field, vnetConfig.portError); - jobjectArray assignedAddrArrayObj = env->NewObjectArray( - vnetConfig.assignedAddressCount, InetSocketAddress_class, NULL); - if(env->ExceptionCheck() || assignedAddrArrayObj == NULL) - { - LOGE("Error creating InetSocketAddress[] array"); - return NULL; - } - - for(unsigned int i = 0; i < vnetConfig.assignedAddressCount; ++i) - { - jobject inetAddrObj = newInetSocketAddress(env, vnetConfig.assignedAddresses[i]); - env->SetObjectArrayElement(assignedAddrArrayObj, i, inetAddrObj); - if(env->ExceptionCheck()) - { - LOGE("Error assigning InetSocketAddress to array"); - return NULL; - } - - env->DeleteLocalRef(inetAddrObj); - } + jobjectArray assignedAddrArrayObj = newInetSocketAddressArray(env, vnetConfig.assignedAddresses, vnetConfig.assignedAddressCount); env->SetObjectField(vnetConfigObj, VirtualNetworkConfig_assignedAddresses_field, assignedAddrArrayObj); - jobjectArray routesArrayObj = env->NewObjectArray( - vnetConfig.routeCount, VirtualNetworkRoute_class, NULL); - if(env->ExceptionCheck() || routesArrayObj == NULL) - { - LOGE("Error creating VirtualNetworkRoute[] array"); - return NULL; - } - - for(unsigned int i = 0; i < vnetConfig.routeCount; ++i) - { - jobject routeObj = newVirtualNetworkRoute(env, vnetConfig.routes[i]); - env->SetObjectArrayElement(routesArrayObj, i, routeObj); - if(env->ExceptionCheck()) - { - LOGE("Error assigning VirtualNetworkRoute to array"); - return NULL; - } - - env->DeleteLocalRef(routeObj); - } + jobjectArray routesArrayObj = newVirtualNetworkRouteArray(env, vnetConfig.routes, vnetConfig.routeCount); env->SetObjectField(vnetConfigObj, VirtualNetworkConfig_routes_field, routesArrayObj); @@ -456,3 +398,76 @@ jobject newNodeStatus(JNIEnv *env, const ZT_NodeStatus &status) { return nodeStatusObj; } + +jobjectArray newPeerArray(JNIEnv *env, const ZT_Peer *peers, size_t count) { + return newArrayObject(env, peers, count, Peer_class); +} + +jobjectArray newVirtualNetworkConfigArray(JNIEnv *env, const ZT_VirtualNetworkConfig *networks, size_t count) { + return newArrayObject(env, networks, count, VirtualNetworkConfig_class); +} + +jobjectArray newPeerPhysicalPathArray(JNIEnv *env, const ZT_PeerPhysicalPath *paths, size_t count) { + return newArrayObject(env, paths, count, PeerPhysicalPath_class); +} + +jobjectArray newInetSocketAddressArray(JNIEnv *env, const sockaddr_storage *addresses, size_t count) { + return newArrayObject(env, addresses, count, InetSocketAddress_class); +} + +jobjectArray newVirtualNetworkRouteArray(JNIEnv *env, const ZT_VirtualNetworkRoute *routes, size_t count) { + return newArrayObject(env, routes, count, VirtualNetworkRoute_class); +} + +void newArrayObject_logCount(size_t count) { + LOGE("count > JSIZE_MAX: %zu", count); +} + +void newArrayObject_log(const char *msg) { + LOGE("%s", msg); +} + +jbyteArray newByteArray(JNIEnv *env, const unsigned char *bytes, size_t count) { + + if (count > JSIZE_MAX) { + LOGE("count > JSIZE_MAX: %zu", count); + return NULL; + } + + jsize jCount = static_cast(count); + const jbyte *jBytes = reinterpret_cast(bytes); + + jbyteArray byteArrayObj = env->NewByteArray(jCount); + if(byteArrayObj == NULL) + { + LOGE("NewByteArray returned NULL"); + return NULL; + } + + env->SetByteArrayRegion(byteArrayObj, 0, jCount, jBytes); + if (env->ExceptionCheck()) { + LOGE("Exception when calling SetByteArrayRegion"); + return NULL; + } + + return byteArrayObj; +} + +jbyteArray newByteArray(JNIEnv *env, size_t count) { + + if (count > JSIZE_MAX) { + LOGE("count > JSIZE_MAX: %zu", count); + return NULL; + } + + jsize jCount = static_cast(count); + + jbyteArray byteArrayObj = env->NewByteArray(jCount); + if(byteArrayObj == NULL) + { + LOGE("NewByteArray returned NULL"); + return NULL; + } + + return byteArrayObj; +} diff --git a/java/jni/ZT_jniutils.h b/java/jni/ZT_jniutils.h index 164030ee5..bad093218 100644 --- a/java/jni/ZT_jniutils.h +++ b/java/jni/ZT_jniutils.h @@ -22,6 +22,8 @@ #include #include +#include // for numeric_limits + #if defined(__ANDROID__) #include @@ -75,6 +77,8 @@ } while (false) +const jsize JSIZE_MAX = std::numeric_limits::max(); + jobject createResultObject(JNIEnv *env, ZT_ResultCode code); jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status); jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type); @@ -98,4 +102,62 @@ jobject newVirtualNetworkDNS(JNIEnv *env, const ZT_VirtualNetworkDNS &dns); jobject newNodeStatus(JNIEnv *env, const ZT_NodeStatus &status); +jobjectArray newPeerArray(JNIEnv *env, const ZT_Peer *peers, size_t count); + +jobjectArray newVirtualNetworkConfigArray(JNIEnv *env, const ZT_VirtualNetworkConfig *networks, size_t count); + +jobjectArray newPeerPhysicalPathArray(JNIEnv *env, const ZT_PeerPhysicalPath *paths, size_t count); + +jobjectArray newInetSocketAddressArray(JNIEnv *env, const sockaddr_storage *addresses, size_t count); + +jobjectArray newVirtualNetworkRouteArray(JNIEnv *env, const ZT_VirtualNetworkRoute *routes, size_t count); + +// +// log functions only for newArrayObject below +// +void newArrayObject_logCount(size_t count); +void newArrayObject_log(const char *msg); + +// +// function template for creating array objects +// +template +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(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); + #endif // ZT_jniutils_h_ diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index 4d52735e7..557a887be 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -164,20 +164,10 @@ namespace { return; } - jbyteArray dataArray = env->NewByteArray(frameLength); + const unsigned char *bytes = static_cast(frameData); + jbyteArray dataArray = newByteArray(env, bytes, frameLength); if(env->ExceptionCheck() || dataArray == NULL) { - LOGE("Couldn't create frame data array"); - return; - } - - void *data = env->GetPrimitiveArrayCritical(dataArray, NULL); - memcpy(data, frameData, frameLength); - env->ReleasePrimitiveArrayCritical(dataArray, data, 0); - - if(env->ExceptionCheck()) - { - LOGE("Error setting frame data to array"); return; } @@ -304,16 +294,13 @@ namespace { if (bufferLength >= 0) { LOGD("JNI: Write file: %s", p); - // set operation - jbyteArray bufferObj = env->NewByteArray(bufferLength); + const unsigned char *bytes = static_cast(buffer); + jbyteArray bufferObj = newByteArray(env, bytes, bufferLength); if(env->ExceptionCheck() || bufferObj == NULL) { - LOGE("Error creating byte array buffer!"); return; } - env->SetByteArrayRegion(bufferObj, 0, bufferLength, (jbyte*)buffer); - env->CallIntMethod(ref->dataStorePutListener, DataStorePutListener_onDataStorePut_method, nameStr, bufferObj, secure); @@ -375,10 +362,9 @@ namespace { return -103; // out of memory } - jbyteArray bufferObj = env->NewByteArray(bufferLength); - if(bufferObj == NULL) + jbyteArray bufferObj = newByteArray(env, bufferLength); + if(env->ExceptionCheck() || bufferObj == NULL) { - LOGE("Error creating byte[] buffer of size: %u", bufferLength); return -104; } @@ -424,8 +410,13 @@ namespace { } jobject remoteAddressObj = newInetSocketAddress(env, *remoteAddress); - jbyteArray bufferObj = env->NewByteArray(bufferSize); - env->SetByteArrayRegion(bufferObj, 0, bufferSize, (jbyte*)buffer); + const unsigned char *bytes = static_cast(buffer); + jbyteArray bufferObj = newByteArray(env, bytes, bufferSize); + if (env->ExceptionCheck() || bufferObj == NULL) + { + return -101; + } + int retval = env->CallIntMethod(ref->packetSender, PacketSender_onSendPacketRequested_method, localSocket, remoteAddressObj, bufferObj); LOGV("JNI Packet Sender returned: %d", retval); @@ -1207,29 +1198,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers( return NULL; } - jobjectArray peerArrayObj = env->NewObjectArray( - peerList->peerCount, Peer_class, NULL); - - if(env->ExceptionCheck() || peerArrayObj == NULL) - { - LOGE("Error creating Peer[] array"); - ZT_Node_freeQueryResult(node, peerList); - return NULL; - } - - - for(unsigned int i = 0; i < peerList->peerCount; ++i) - { - jobject peerObj = newPeer(env, peerList->peers[i]); - env->SetObjectArrayElement(peerArrayObj, i, peerObj); - if(env->ExceptionCheck()) - { - LOGE("Error assigning Peer object to array"); - break; - } - - env->DeleteLocalRef(peerObj); - } + jobjectArray peerArrayObj = newPeerArray(env, peerList->peers, peerList->peerCount); ZT_Node_freeQueryResult(node, peerList); peerList = NULL; @@ -1254,27 +1223,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networks( return NULL; } - jobjectArray networkListObject = env->NewObjectArray( - networkList->networkCount, VirtualNetworkConfig_class, NULL); - if(env->ExceptionCheck() || networkListObject == NULL) - { - LOGE("Error creating VirtualNetworkConfig[] array"); - ZT_Node_freeQueryResult(node, networkList); - return NULL; - } - - for(unsigned int i = 0; i < networkList->networkCount; ++i) - { - jobject networkObject = newNetworkConfig(env, networkList->networks[i]); - env->SetObjectArrayElement(networkListObject, i, networkObject); - if(env->ExceptionCheck()) - { - LOGE("Error assigning VirtualNetworkConfig object to array"); - break; - } - - env->DeleteLocalRef(networkObject); - } + jobjectArray networkListObject = newVirtualNetworkConfigArray(env, networkList->networks, networkList->networkCount); ZT_Node_freeQueryResult(node, networkList);