From 8a8ff6b081a0cac0d6a9580f040f696f7bb46472 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Thu, 8 May 2014 14:17:45 +0800 Subject: [PATCH] add jni functions --- src/android.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ src/android.h | 9 +++++ src/local.c | 16 ++++++++ 3 files changed, 127 insertions(+) create mode 100644 src/android.cpp create mode 100644 src/android.h diff --git a/src/android.cpp b/src/android.cpp new file mode 100644 index 00000000..042289e4 --- /dev/null +++ b/src/android.cpp @@ -0,0 +1,102 @@ +#define LOG_TAG "Shadowsocks" + +#include "android.h" +#include +#include +#include +#include +#include + +#define LOGI(...) do { __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); } while(0) +#define LOGW(...) do { __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); } while(0) +#define LOGE(...) do { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__); } while(0) + +/* + * This is called by the VM when the shared library is first loaded. + */ + +typedef union { + JNIEnv* env; + void* venv; +} UnionJNIEnvToVoid; + +static UnionJNIEnvToVoid uenv; +static jmethodID newProtectedSocketMethod = NULL; +static jmethodID freeProtectedSocketMethod = NULL; +static jclass clazz = NULL; + +static const char *classPathName = "com/github/shadowsocks/Socket"; + +/* + * Register several native methods for one class. + */ +static int registerNativeMethods(JNIEnv* env, const char* className) +{ + if (clazz == NULL) + { + clazz = env->FindClass(className); + } + if (clazz == NULL) + { + LOGE("Native registration unable to find class '%s'", className); + return JNI_FALSE; + } + newProtectedSocketMethod = env->GetStaticMethodID(clazz, "newProtectedSocket", "()I"); + if (newProtectedSocketMethod < 0) + { + LOGE("RegisterNatives failed for newProtectedSocketMethod"); + return JNI_FALSE; + } + freeProtectedSocketMethod = env->GetStaticMethodID(clazz, "freeProtectedSocket", "(I)V"); + if (freeProtectedSocketMethod < 0) + { + LOGE("RegisterNatives failed for freeProtectedSocketMethod"); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +jint new_protected_socket() +{ + if (newProtectedSocketMethod != NULL) + { + JNIEnv* env = uenv.env; + return (*env)->CallStaticIntMethod(env, SocketCls, newProtectedSocketMethod); + } + return -1; +} + +void free_protected_socket(jint fd) +{ + if (newProtectedSocketMethod != NULL) + { + JNIEnv* env = uenv.env; + (*env)->CallStaticVoidMethod(env, SocketCls, freeProtectedSocketMethod, fd); + } +} + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + uenv.venv = NULL; + jint result = -1; + JNIEnv* env = NULL; + + LOGI("JNI_OnLoad"); + + if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) { + LOGE("ERROR: GetEnv failed"); + goto bail; + } + env = uenv.env; + + if (registerNativeMethods(env, classPathName) != JNI_TRUE) { + LOGE("ERROR: registerNatives failed"); + goto bail; + } + + result = JNI_VERSION_1_4; + +bail: + return result; +} diff --git a/src/android.h b/src/android.h new file mode 100644 index 00000000..07529909 --- /dev/null +++ b/src/android.h @@ -0,0 +1,9 @@ +#ifndef _JNI_H +#define _JNI_H + +#include + +jint new_protected_socket(); +void free_protected_socket(jint fd); + +#endif // _JNI_H diff --git a/src/local.c b/src/local.c index 3abd9117..40ddeab9 100644 --- a/src/local.c +++ b/src/local.c @@ -8,6 +8,10 @@ #include #include +#ifdef ANDROID +#include "android.h" +#endif + #ifndef __MINGW32__ #include #include @@ -757,7 +761,11 @@ static void close_and_free_remote(EV_P_ struct remote *remote) ev_timer_stop(EV_A_ &remote->send_ctx->watcher); ev_io_stop(EV_A_ &remote->send_ctx->io); ev_io_stop(EV_A_ &remote->recv_ctx->io); +#ifdef ANDROID + free_protect_fd(remote->fd); +#else close(remote->fd); +#endif free_remote(remote); } } @@ -868,8 +876,16 @@ static struct remote* connect_to_remote(struct listen_ctx *listener, return NULL; } +#ifdef ANDROID + + sockfd = new_protect_socket(); + +#else + sockfd = socket(remote_res->ai_family, remote_res->ai_socktype, remote_res->ai_protocol); +#endif + if (sockfd < 0) { ERROR("socket");