Moved JNI wrapper into separate file. Updated shared_jni_lib build target
This commit is contained in:
23
Makefile
23
Makefile
@@ -295,13 +295,16 @@ libzt_socket_layer:
|
|||||||
$(CXX) $(CXXFLAGS) -c src/libzt.cpp \
|
$(CXX) $(CXXFLAGS) -c src/libzt.cpp \
|
||||||
$(ZT_DEFS) $(ZT_INCLUDES) $(STACK_INCLUDES) $(LIBZT_DEFS) $(LIBZT_INCLUDES) $(STACK_DRIVER_DEFS)
|
$(ZT_DEFS) $(ZT_INCLUDES) $(STACK_INCLUDES) $(LIBZT_DEFS) $(LIBZT_INCLUDES) $(STACK_DRIVER_DEFS)
|
||||||
|
|
||||||
|
jni_socket_wrapper:
|
||||||
|
$(CXX) $(CXXFLAGS) -DSDK_JNI -c src/libztJNI.cpp \
|
||||||
|
$(ZT_DEFS) $(ZT_INCLUDES) $(STACK_INCLUDES) $(LIBZT_DEFS) $(LIBZT_INCLUDES) $(STACK_DRIVER_DEFS)
|
||||||
|
|
||||||
utilities:
|
utilities:
|
||||||
$(CXX) $(CXXFLAGS) -c src/Platform.cpp \
|
$(CXX) $(CXXFLAGS) -c src/Platform.cpp \
|
||||||
$(LIBZT_INCLUDES)
|
$(LIBZT_INCLUDES)
|
||||||
$(CXX) $(CXXFLAGS) -c src/Utilities.cpp \
|
$(CXX) $(CXXFLAGS) -c src/Utilities.cpp \
|
||||||
$(ZT_DEFS) $(ZT_INCLUDES) $(LIBZT_INCLUDES) $(STACK_DRIVER_DEFS)
|
$(ZT_DEFS) $(ZT_INCLUDES) $(LIBZT_INCLUDES) $(STACK_DRIVER_DEFS)
|
||||||
|
|
||||||
|
|
||||||
win_dll: lwip lwip_driver libzt_socket_layer utilities $(ZTO_OBJS)
|
win_dll: lwip lwip_driver libzt_socket_layer utilities $(ZTO_OBJS)
|
||||||
# First we use mingw to build our DLL
|
# First we use mingw to build our DLL
|
||||||
@mkdir -p $(BUILD) obj
|
@mkdir -p $(BUILD) obj
|
||||||
@@ -313,6 +316,16 @@ win_dll: lwip lwip_driver libzt_socket_layer utilities $(ZTO_OBJS)
|
|||||||
# lib /machine:x64 /def:libzt.def
|
# lib /machine:x64 /def:libzt.def
|
||||||
# or just execute: makelib
|
# or just execute: makelib
|
||||||
|
|
||||||
|
shared_lib: lwip lwip_driver libzt_socket_layer utilities $(ZTO_OBJS)
|
||||||
|
@mkdir -p $(BUILD) obj
|
||||||
|
mv *.o obj
|
||||||
|
$(CXX) $(CXXFLAGS) -shared -o $(BUILD)/libzt.so obj/*.o
|
||||||
|
|
||||||
|
shared_jni_lib: lwip lwip_driver libzt_socket_layer jni_socket_wrapper utilities $(ZTO_OBJS)
|
||||||
|
@mkdir -p $(BUILD) obj
|
||||||
|
mv *.o obj
|
||||||
|
$(CXX) $(CXXFLAGS) -shared -o $(BUILD)/libzt.so obj/*.o
|
||||||
|
|
||||||
ifeq ($(STACK_PICO),1)
|
ifeq ($(STACK_PICO),1)
|
||||||
static_lib: picotcp picotcp_driver libzt_socket_layer utilities $(ZTO_OBJS)
|
static_lib: picotcp picotcp_driver libzt_socket_layer utilities $(ZTO_OBJS)
|
||||||
@mkdir -p $(BUILD) obj
|
@mkdir -p $(BUILD) obj
|
||||||
@@ -354,14 +367,6 @@ macos_app_framework:
|
|||||||
cd examples/apple/ZeroTierSDK_Apple; xcodebuild -configuration Debug \
|
cd examples/apple/ZeroTierSDK_Apple; xcodebuild -configuration Debug \
|
||||||
-scheme ZeroTierSDK_OSX build SYMROOT="../../../$(BUILD)/macos_app_framework"
|
-scheme ZeroTierSDK_OSX build SYMROOT="../../../$(BUILD)/macos_app_framework"
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
## Java JNI ##
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
shared_jni_lib: picotcp $(ZTO_OBJS)
|
|
||||||
$(CXX) $(CXXFLAGS) $(TAP_FILES) $(STACK_DRIVER_FILES) $(ZTO_OBJS) $(INCLUDES) \
|
|
||||||
$(PICO_LIB) -dynamiclib -o $(SHARED_JNI_LIB)
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
## Python module ##
|
## Python module ##
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ void disableTaps()
|
|||||||
|
|
||||||
void zts_get_ipv4_address(const char *nwid, char *addrstr, const size_t addrlen)
|
void zts_get_ipv4_address(const char *nwid, char *addrstr, const size_t addrlen)
|
||||||
{
|
{
|
||||||
DEBUG_EXTRA();
|
// DEBUG_EXTRA();
|
||||||
if (ZeroTier::zt1Service) {
|
if (ZeroTier::zt1Service) {
|
||||||
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
||||||
ZeroTier::VirtualTap *tap = getTapByNWID(nwid_int);
|
ZeroTier::VirtualTap *tap = getTapByNWID(nwid_int);
|
||||||
@@ -286,7 +286,7 @@ void zts_get_ipv4_address(const char *nwid, char *addrstr, const size_t addrlen)
|
|||||||
|
|
||||||
void zts_get_ipv6_address(const char *nwid, char *addrstr, size_t addrlen)
|
void zts_get_ipv6_address(const char *nwid, char *addrstr, size_t addrlen)
|
||||||
{
|
{
|
||||||
DEBUG_EXTRA();
|
// DEBUG_EXTRA();
|
||||||
if (ZeroTier::zt1Service) {
|
if (ZeroTier::zt1Service) {
|
||||||
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
uint64_t nwid_int = strtoull(nwid, NULL, 16);
|
||||||
ZeroTier::VirtualTap *tap = getTapByNWID(nwid_int);
|
ZeroTier::VirtualTap *tap = getTapByNWID(nwid_int);
|
||||||
@@ -309,7 +309,7 @@ void zts_get_ipv6_address(const char *nwid, char *addrstr, size_t addrlen)
|
|||||||
|
|
||||||
int zts_has_ipv4_address(const char *nwid)
|
int zts_has_ipv4_address(const char *nwid)
|
||||||
{
|
{
|
||||||
DEBUG_EXTRA();
|
// DEBUG_EXTRA();
|
||||||
char ipv4_addr[INET_ADDRSTRLEN];
|
char ipv4_addr[INET_ADDRSTRLEN];
|
||||||
memset(ipv4_addr, 0, INET_ADDRSTRLEN);
|
memset(ipv4_addr, 0, INET_ADDRSTRLEN);
|
||||||
zts_get_ipv4_address(nwid, ipv4_addr, INET_ADDRSTRLEN);
|
zts_get_ipv4_address(nwid, ipv4_addr, INET_ADDRSTRLEN);
|
||||||
@@ -318,7 +318,7 @@ int zts_has_ipv4_address(const char *nwid)
|
|||||||
|
|
||||||
int zts_has_ipv6_address(const char *nwid)
|
int zts_has_ipv6_address(const char *nwid)
|
||||||
{
|
{
|
||||||
DEBUG_EXTRA();
|
// DEBUG_EXTRA();
|
||||||
char ipv6_addr[INET6_ADDRSTRLEN];
|
char ipv6_addr[INET6_ADDRSTRLEN];
|
||||||
memset(ipv6_addr, 0, INET6_ADDRSTRLEN);
|
memset(ipv6_addr, 0, INET6_ADDRSTRLEN);
|
||||||
zts_get_ipv6_address(nwid, ipv6_addr, INET6_ADDRSTRLEN);
|
zts_get_ipv6_address(nwid, ipv6_addr, INET6_ADDRSTRLEN);
|
||||||
@@ -327,11 +327,10 @@ int zts_has_ipv6_address(const char *nwid)
|
|||||||
|
|
||||||
int zts_has_address(const char *nwid)
|
int zts_has_address(const char *nwid)
|
||||||
{
|
{
|
||||||
DEBUG_EXTRA();
|
// DEBUG_EXTRA();
|
||||||
return zts_has_ipv4_address(nwid) || zts_has_ipv6_address(nwid);
|
return zts_has_ipv4_address(nwid) || zts_has_ipv6_address(nwid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void zts_get_6plane_addr(char *addr, const char *nwid, const char *devID)
|
void zts_get_6plane_addr(char *addr, const char *nwid, const char *devID)
|
||||||
{
|
{
|
||||||
DEBUG_EXTRA();
|
DEBUG_EXTRA();
|
||||||
@@ -537,99 +536,6 @@ void zts_allow_http_control(bool allowed)
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(SDK_JNI)
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1start(JNIEnv *env, jobject thisObj, jstring path) {
|
|
||||||
if (path) {
|
|
||||||
homeDir = env->GetStringUTFChars(path, NULL);
|
|
||||||
zts_start(homeDir.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Shuts down ZeroTier service and SOCKS5 Proxy server
|
|
||||||
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1stop(JNIEnv *env, jobject thisObj) {
|
|
||||||
if (ZeroTier::zt1Service) {
|
|
||||||
zts_stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns whether the ZeroTier service is running
|
|
||||||
JNIEXPORT jboolean JNICALL Java_zerotier_ZeroTier_ztjni_1running(
|
|
||||||
JNIEnv *env, jobject thisObj)
|
|
||||||
{
|
|
||||||
return zts_running();
|
|
||||||
}
|
|
||||||
// Returns path for ZT config/data files
|
|
||||||
JNIEXPORT jstring JNICALL Java_zerotier_ZeroTier_ztjni_1homepath(
|
|
||||||
JNIEnv *env, jobject thisObj)
|
|
||||||
{
|
|
||||||
// TODO: fix, should copy into given arg
|
|
||||||
// return (*env).NewStringUTF(zts_get_homepath());
|
|
||||||
return (*env).NewStringUTF("");
|
|
||||||
}
|
|
||||||
// Join a network
|
|
||||||
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1join(
|
|
||||||
JNIEnv *env, jobject thisObj, jstring nwid)
|
|
||||||
{
|
|
||||||
const char *nwidstr;
|
|
||||||
if (nwid) {
|
|
||||||
nwidstr = env->GetStringUTFChars(nwid, NULL);
|
|
||||||
zts_join(nwidstr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Leave a network
|
|
||||||
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1leave(
|
|
||||||
JNIEnv *env, jobject thisObj, jstring nwid)
|
|
||||||
{
|
|
||||||
const char *nwidstr;
|
|
||||||
if (nwid) {
|
|
||||||
nwidstr = env->GetStringUTFChars(nwid, NULL);
|
|
||||||
zts_leave(nwidstr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// FIXME: Re-implemented to make it play nicer with the C-linkage required for Xcode integrations
|
|
||||||
// Now only returns first assigned address per network. Shouldn't normally be a problem
|
|
||||||
JNIEXPORT jobject JNICALL Java_zerotier_ZeroTier_ztjni_1get_1ipv4_1address(
|
|
||||||
JNIEnv *env, jobject thisObj, jstring nwid)
|
|
||||||
{
|
|
||||||
const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
|
|
||||||
char address_string[INET_ADDRSTRLEN];
|
|
||||||
memset(address_string, 0, INET_ADDRSTRLEN);
|
|
||||||
zts_get_ipv4_address(nwid_str, address_string, INET_ADDRSTRLEN);
|
|
||||||
jclass clazz = (*env).FindClass("java/util/ArrayList");
|
|
||||||
jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "<init>", "()V"));
|
|
||||||
jstring _str = (*env).NewStringUTF(address_string);
|
|
||||||
env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
|
|
||||||
return addresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jobject JNICALL Java_zerotier_ZeroTier_ztjni_1get_1ipv6_1address(
|
|
||||||
JNIEnv *env, jobject thisObj, jstring nwid)
|
|
||||||
{
|
|
||||||
const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
|
|
||||||
char address_string[INET6_ADDRSTRLEN];
|
|
||||||
memset(address_string, 0, INET6_ADDRSTRLEN);
|
|
||||||
zts_get_ipv6_address(nwid_str, address_string, INET6_ADDRSTRLEN);
|
|
||||||
jclass clazz = (*env).FindClass("java/util/ArrayList");
|
|
||||||
jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "<init>", "()V"));
|
|
||||||
jstring _str = (*env).NewStringUTF(address_string);
|
|
||||||
env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
|
|
||||||
return addresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the device is in integer form
|
|
||||||
JNIEXPORT jint Java_zerotier_ZeroTier_ztjni_1get_1device_1id()
|
|
||||||
{
|
|
||||||
return zts_get_device_id(NULL); // TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SDK_JNI
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
190
src/libzt.cpp
190
src/libzt.cpp
@@ -534,196 +534,6 @@ int zts_del_dns_nameserver(struct sockaddr *addr)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
/* SDK Socket API (Java Native Interface JNI) */
|
|
||||||
/* JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME */
|
|
||||||
/****************************************************************************/
|
|
||||||
|
|
||||||
#if defined(SDK_JNI)
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1sendto(
|
|
||||||
JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr)
|
|
||||||
{
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
jclass cls = (*env).GetObjectClass( ztaddr);
|
|
||||||
jfieldID f = (*env).GetFieldID( cls, "port", "I");
|
|
||||||
addr.sin_port = htons((*env).GetIntField( ztaddr, f));
|
|
||||||
f = (*env).GetFieldID( cls, "_rawAddr", "J");
|
|
||||||
addr.sin_addr.s_addr = (*env).GetLongField( ztaddr, f);
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
//LOGV("zt_sendto(): fd = %d\naddr = %s\nport=%d", fd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
|
||||||
// TODO: Optimize this
|
|
||||||
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
|
||||||
char * bufp = (char *)malloc(sizeof(char)*len);
|
|
||||||
memcpy(bufp, body, len);
|
|
||||||
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
|
||||||
// "connect" and send buffer contents
|
|
||||||
int sent_bytes = zts_sendto(fd, body, len, flags, (struct sockaddr *)&addr, sizeof(addr));
|
|
||||||
return sent_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1recvfrom(
|
|
||||||
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint len, jint flags, jobject ztaddr)
|
|
||||||
{
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
jbyte *body = (*env).GetByteArrayElements( buf, 0);
|
|
||||||
unsigned char buffer[ZT_SDK_MTU];
|
|
||||||
int payload_offset = sizeof(int32_t) + sizeof(struct sockaddr_storage);
|
|
||||||
int rxbytes = zts_recvfrom(fd, &buffer, len, flags, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr_storage));
|
|
||||||
if (rxbytes > 0)
|
|
||||||
memcpy(body, (jbyte*)buffer + payload_offset, rxbytes);
|
|
||||||
(*env).ReleaseByteArrayElements( buf, body, 0);
|
|
||||||
// Update fields of Java ZTAddress object
|
|
||||||
jfieldID fid;
|
|
||||||
jclass cls = (*env).GetObjectClass( ztaddr);
|
|
||||||
fid = (*env).GetFieldID( cls, "port", "I");
|
|
||||||
(*env).SetIntField( ztaddr, fid, addr.sin_port);
|
|
||||||
fid = (*env).GetFieldID( cls,"_rawAddr", "J");
|
|
||||||
(*env).SetLongField( ztaddr, fid,addr.sin_addr.s_addr);
|
|
||||||
return rxbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1send(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, int flags)
|
|
||||||
{
|
|
||||||
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
|
||||||
char * bufp = (char *)malloc(sizeof(char)*len);
|
|
||||||
memcpy(bufp, body, len);
|
|
||||||
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
|
||||||
int written_bytes = zts_write(fd, body, len);
|
|
||||||
return written_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1write(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jarray buf, jint len)
|
|
||||||
{
|
|
||||||
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
|
||||||
char * bufp = (char *)malloc(sizeof(char)*len);
|
|
||||||
memcpy(bufp, body, len);
|
|
||||||
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
|
||||||
int written_bytes = zts_write(fd, body, len);
|
|
||||||
return written_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1read(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jarray buf, jint len)
|
|
||||||
{
|
|
||||||
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
|
||||||
int read_bytes = read(fd, body, len);
|
|
||||||
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
|
||||||
return read_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1setsockopt(
|
|
||||||
JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jint level, jint optname, jint optval, jint optlen) {
|
|
||||||
return zts_setsockopt(fd, level, optname, (const void*)optval, optlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockopt(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jint level, jint optname, jint optval, jint optlen) {
|
|
||||||
return zts_getsockopt(fd, level, optname, (void*)optval, (socklen_t *)optlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1socket(JNIEnv *env, jobject thisObj,
|
|
||||||
jint family, jint type, jint protocol) {
|
|
||||||
return zts_socket(family, type, protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1connect(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jstring addrstr, jint port) {
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
const char *str = (*env).GetStringUTFChars( addrstr, 0);
|
|
||||||
addr.sin_addr.s_addr = inet_addr(str);
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = htons( port );
|
|
||||||
(*env).ReleaseStringUTFChars( addrstr, str);
|
|
||||||
return zts_connect(fd, (struct sockaddr *)&addr, sizeof(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1bind(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jstring addrstr, jint port) {
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
const char *str = (*env).GetStringUTFChars( addrstr, 0);
|
|
||||||
DEBUG_INFO("fd=%d, addr=%s, port=%d", fd, str, port);
|
|
||||||
addr.sin_addr.s_addr = inet_addr(str);
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = htons( port );
|
|
||||||
(*env).ReleaseStringUTFChars( addrstr, str);
|
|
||||||
return zts_bind(fd, (struct sockaddr *)&addr, sizeof(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1accept4(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jstring addrstr, jint port, jint flags) {
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
char *str;
|
|
||||||
// = env->GetStringUTFChars(addrstr, NULL);
|
|
||||||
(*env).ReleaseStringUTFChars( addrstr, str);
|
|
||||||
addr.sin_addr.s_addr = inet_addr(str);
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = htons( port );
|
|
||||||
return zts_accept4(fd, (struct sockaddr *)&addr, sizeof(addr), flags);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1accept(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jstring addrstr, jint port) {
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
// TODO: Send addr info back to Javaland
|
|
||||||
addr.sin_addr.s_addr = inet_addr("");
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = htons( port );
|
|
||||||
return zts_accept(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1listen(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, int backlog) {
|
|
||||||
return zts_listen(fd, backlog);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1close(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd) {
|
|
||||||
return zts_close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockname(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jobject ztaddr) {
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
int err = zts_getsockname(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
|
|
||||||
jfieldID fid;
|
|
||||||
jclass cls = (*env).GetObjectClass(ztaddr);
|
|
||||||
fid = (*env).GetFieldID( cls, "port", "I");
|
|
||||||
(*env).SetIntField( ztaddr, fid, addr.sin_port);
|
|
||||||
fid = (*env).GetFieldID( cls,"_rawAddr", "J");
|
|
||||||
(*env).SetLongField( ztaddr, fid,addr.sin_addr.s_addr);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getpeername(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jobject ztaddr) {
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
int err = zts_getpeername(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
|
|
||||||
jfieldID fid;
|
|
||||||
jclass cls = (*env).GetObjectClass( ztaddr);
|
|
||||||
fid = (*env).GetFieldID( cls, "port", "I");
|
|
||||||
(*env).SetIntField( ztaddr, fid, addr.sin_port);
|
|
||||||
fid = (*env).GetFieldID( cls,"_rawAddr", "J");
|
|
||||||
(*env).SetLongField( ztaddr, fid,addr.sin_addr.s_addr);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1fcntl(JNIEnv *env, jobject thisObj,
|
|
||||||
jint fd, jint cmd, jint flags) {
|
|
||||||
return zts_fcntl(fd,cmd,flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // SDK_JNI
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
321
src/libztJNI.cpp
Normal file
321
src/libztJNI.cpp
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
* ZeroTier SDK - Network Virtualization Everywhere
|
||||||
|
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* --
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the license by purchasing
|
||||||
|
* a commercial license. Buying such a license is mandatory as soon as you
|
||||||
|
* develop commercial closed-source software that incorporates or links
|
||||||
|
* directly against ZeroTier software without disclosing the source code
|
||||||
|
* of your own application.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* Javs JNI wrapper for partially-POSIX-compliant socket API
|
||||||
|
* JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(SDK_JNI)
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include "libzt.h"
|
||||||
|
#include "ZT1Service.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/* Java JNI Wrapper for ZeroTier Socket API */
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1sendto(
|
||||||
|
JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr)
|
||||||
|
{
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
jclass cls = (*env).GetObjectClass( ztaddr);
|
||||||
|
jfieldID f = (*env).GetFieldID( cls, "port", "I");
|
||||||
|
addr.sin_port = htons((*env).GetIntField( ztaddr, f));
|
||||||
|
f = (*env).GetFieldID( cls, "_rawAddr", "J");
|
||||||
|
addr.sin_addr.s_addr = (*env).GetLongField( ztaddr, f);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
//LOGV("zt_sendto(): fd = %d\naddr = %s\nport=%d", fd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
||||||
|
// TODO: Optimize this
|
||||||
|
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
||||||
|
char * bufp = (char *)malloc(sizeof(char)*len);
|
||||||
|
memcpy(bufp, body, len);
|
||||||
|
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
||||||
|
// "connect" and send buffer contents
|
||||||
|
int sent_bytes = zts_sendto(fd, body, len, flags, (struct sockaddr *)&addr, sizeof(addr));
|
||||||
|
return sent_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1recvfrom(
|
||||||
|
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint len, jint flags, jobject ztaddr)
|
||||||
|
{
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
jbyte *body = (*env).GetByteArrayElements( buf, 0);
|
||||||
|
unsigned char buffer[ZT_SDK_MTU];
|
||||||
|
int payload_offset = sizeof(int32_t) + sizeof(struct sockaddr_storage);
|
||||||
|
int rxbytes = zts_recvfrom(fd, &buffer, len, flags, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr_storage));
|
||||||
|
if (rxbytes > 0)
|
||||||
|
memcpy(body, (jbyte*)buffer + payload_offset, rxbytes);
|
||||||
|
(*env).ReleaseByteArrayElements( buf, body, 0);
|
||||||
|
// Update fields of Java ZTAddress object
|
||||||
|
jfieldID fid;
|
||||||
|
jclass cls = (*env).GetObjectClass( ztaddr);
|
||||||
|
fid = (*env).GetFieldID( cls, "port", "I");
|
||||||
|
(*env).SetIntField( ztaddr, fid, addr.sin_port);
|
||||||
|
fid = (*env).GetFieldID( cls,"_rawAddr", "J");
|
||||||
|
(*env).SetLongField( ztaddr, fid,addr.sin_addr.s_addr);
|
||||||
|
return rxbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1send(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, int flags)
|
||||||
|
{
|
||||||
|
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
||||||
|
char * bufp = (char *)malloc(sizeof(char)*len);
|
||||||
|
memcpy(bufp, body, len);
|
||||||
|
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
||||||
|
int written_bytes = zts_write(fd, body, len);
|
||||||
|
return written_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1write(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jarray buf, jint len)
|
||||||
|
{
|
||||||
|
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
||||||
|
char * bufp = (char *)malloc(sizeof(char)*len);
|
||||||
|
memcpy(bufp, body, len);
|
||||||
|
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
||||||
|
int written_bytes = zts_write(fd, body, len);
|
||||||
|
return written_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1read(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jarray buf, jint len)
|
||||||
|
{
|
||||||
|
jbyte *body = (*env).GetByteArrayElements((_jbyteArray *)buf, 0);
|
||||||
|
int read_bytes = read(fd, body, len);
|
||||||
|
(*env).ReleaseByteArrayElements((_jbyteArray *)buf, body, 0);
|
||||||
|
return read_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1setsockopt(
|
||||||
|
JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jint level, jint optname, jint optval, jint optlen) {
|
||||||
|
return zts_setsockopt(fd, level, optname, (const void*)optval, optlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockopt(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jint level, jint optname, jint optval, jint optlen) {
|
||||||
|
return zts_getsockopt(fd, level, optname, (void*)optval, (socklen_t *)optlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1socket(JNIEnv *env, jobject thisObj,
|
||||||
|
jint family, jint type, jint protocol) {
|
||||||
|
return zts_socket(family, type, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1connect(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jstring addrstr, jint port) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
const char *str = (*env).GetStringUTFChars( addrstr, 0);
|
||||||
|
addr.sin_addr.s_addr = inet_addr(str);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons( port );
|
||||||
|
(*env).ReleaseStringUTFChars( addrstr, str);
|
||||||
|
return zts_connect(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1bind(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jstring addrstr, jint port) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
const char *str = (*env).GetStringUTFChars( addrstr, 0);
|
||||||
|
DEBUG_INFO("fd=%d, addr=%s, port=%d", fd, str, port);
|
||||||
|
addr.sin_addr.s_addr = inet_addr(str);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons( port );
|
||||||
|
(*env).ReleaseStringUTFChars( addrstr, str);
|
||||||
|
return zts_bind(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1accept4(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jstring addrstr, jint port, jint flags) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
char *str;
|
||||||
|
// = env->GetStringUTFChars(addrstr, NULL);
|
||||||
|
(*env).ReleaseStringUTFChars( addrstr, str);
|
||||||
|
addr.sin_addr.s_addr = inet_addr(str);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons( port );
|
||||||
|
return zts_accept4(fd, (struct sockaddr *)&addr, sizeof(addr), flags);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1accept(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jstring addrstr, jint port) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
// TODO: Send addr info back to Javaland
|
||||||
|
addr.sin_addr.s_addr = inet_addr("");
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons( port );
|
||||||
|
return zts_accept(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1listen(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, int backlog) {
|
||||||
|
return zts_listen(fd, backlog);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1close(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd) {
|
||||||
|
return zts_close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getsockname(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jobject ztaddr) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int err = zts_getsockname(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
|
||||||
|
jfieldID fid;
|
||||||
|
jclass cls = (*env).GetObjectClass(ztaddr);
|
||||||
|
fid = (*env).GetFieldID( cls, "port", "I");
|
||||||
|
(*env).SetIntField( ztaddr, fid, addr.sin_port);
|
||||||
|
fid = (*env).GetFieldID( cls,"_rawAddr", "J");
|
||||||
|
(*env).SetLongField( ztaddr, fid,addr.sin_addr.s_addr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1getpeername(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jobject ztaddr) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int err = zts_getpeername(fd, (struct sockaddr *)&addr, (socklen_t *)sizeof(struct sockaddr));
|
||||||
|
jfieldID fid;
|
||||||
|
jclass cls = (*env).GetObjectClass( ztaddr);
|
||||||
|
fid = (*env).GetFieldID( cls, "port", "I");
|
||||||
|
(*env).SetIntField( ztaddr, fid, addr.sin_port);
|
||||||
|
fid = (*env).GetFieldID( cls,"_rawAddr", "J");
|
||||||
|
(*env).SetLongField( ztaddr, fid,addr.sin_addr.s_addr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_zerotier_ZeroTier_ztjni_1fcntl(JNIEnv *env, jobject thisObj,
|
||||||
|
jint fd, jint cmd, jint flags) {
|
||||||
|
return zts_fcntl(fd,cmd,flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/* Java JNI Wrapper for ZeroTier service controls */
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1start(JNIEnv *env, jobject thisObj, jstring path) {
|
||||||
|
if (path) {
|
||||||
|
zts_start(env->GetStringUTFChars(path, NULL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1startjoin(JNIEnv *env, jobject thisObj, jstring path, jstring nwid) {
|
||||||
|
if (path) {
|
||||||
|
zts_startjoin(env->GetStringUTFChars(path, NULL), env->GetStringUTFChars(nwid, NULL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1stop(JNIEnv *env, jobject thisObj) {
|
||||||
|
zts_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL Java_zerotier_ZeroTier_ztjni_1running(
|
||||||
|
JNIEnv *env, jobject thisObj)
|
||||||
|
{
|
||||||
|
return zts_running();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL Java_zerotier_ZeroTier_ztjni_1homepath(
|
||||||
|
JNIEnv *env, jobject thisObj)
|
||||||
|
{
|
||||||
|
// TODO: fix, should copy into given arg
|
||||||
|
// return (*env).NewStringUTF(zts_get_homepath());
|
||||||
|
return (*env).NewStringUTF("");
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1join(
|
||||||
|
JNIEnv *env, jobject thisObj, jstring nwid)
|
||||||
|
{
|
||||||
|
const char *nwidstr;
|
||||||
|
if (nwid) {
|
||||||
|
nwidstr = env->GetStringUTFChars(nwid, NULL);
|
||||||
|
zts_join(nwidstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1leave(
|
||||||
|
JNIEnv *env, jobject thisObj, jstring nwid)
|
||||||
|
{
|
||||||
|
const char *nwidstr;
|
||||||
|
if (nwid) {
|
||||||
|
nwidstr = env->GetStringUTFChars(nwid, NULL);
|
||||||
|
zts_leave(nwidstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_zerotier_ZeroTier_ztjni_1get_1ipv4_1address(
|
||||||
|
JNIEnv *env, jobject thisObj, jstring nwid)
|
||||||
|
{
|
||||||
|
const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
|
||||||
|
char address_string[INET_ADDRSTRLEN];
|
||||||
|
memset(address_string, 0, INET_ADDRSTRLEN);
|
||||||
|
zts_get_ipv4_address(nwid_str, address_string, INET_ADDRSTRLEN);
|
||||||
|
jclass clazz = (*env).FindClass("java/util/ArrayList");
|
||||||
|
jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "<init>", "()V"));
|
||||||
|
jstring _str = (*env).NewStringUTF(address_string);
|
||||||
|
env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_zerotier_ZeroTier_ztjni_1get_1ipv6_1address(
|
||||||
|
JNIEnv *env, jobject thisObj, jstring nwid)
|
||||||
|
{
|
||||||
|
const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
|
||||||
|
char address_string[INET6_ADDRSTRLEN];
|
||||||
|
memset(address_string, 0, INET6_ADDRSTRLEN);
|
||||||
|
zts_get_ipv6_address(nwid_str, address_string, INET6_ADDRSTRLEN);
|
||||||
|
jclass clazz = (*env).FindClass("java/util/ArrayList");
|
||||||
|
jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "<init>", "()V"));
|
||||||
|
jstring _str = (*env).NewStringUTF(address_string);
|
||||||
|
env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint Java_zerotier_ZeroTier_ztjni_1get_1device_1id()
|
||||||
|
{
|
||||||
|
return zts_get_device_id(NULL); // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SDK_JNI
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user