You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
4.5 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. #define LOG_TAG "Shadowsocks"
  2. #include <android/log.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include "android.h"
  7. #define LOGI(...) do { __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); } while(0)
  8. #define LOGW(...) do { __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); } while(0)
  9. #define LOGE(...) do { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__); } while(0)
  10. /*
  11. * This is called by the VM when the shared library is first loaded.
  12. */
  13. typedef union {
  14. JNIEnv* env;
  15. void* venv;
  16. } UnionJNIEnvToVoid;
  17. typedef unsigned short char16_t;
  18. class String8 {
  19. public:
  20. String8() {
  21. mString = 0;
  22. }
  23. ~String8() {
  24. if (mString) {
  25. free(mString);
  26. }
  27. }
  28. void set(const char16_t* o, size_t numChars) {
  29. if (mString) {
  30. free(mString);
  31. }
  32. mString = (char*) malloc(numChars + 1);
  33. if (!mString) {
  34. return;
  35. }
  36. for (size_t i = 0; i < numChars; i++) {
  37. mString[i] = (char) o[i];
  38. }
  39. mString[numChars] = '\0';
  40. }
  41. const char* string() {
  42. return mString;
  43. }
  44. private:
  45. char* mString;
  46. };
  47. static UnionJNIEnvToVoid uenv;
  48. static jmethodID newProtectedSocketMethod = NULL;
  49. static jmethodID freeProtectedSocketMethod = NULL;
  50. static jclass vpnClazz = NULL;
  51. static jclass daemonClazz = NULL;
  52. int main (int argc, char **argv);
  53. jint Java_com_github_shadowsocks_daemon_exec(JNIEnv *env, jobject thiz, jobjectArray argv) {
  54. int argc = argv ? env->GetArrayLength(argv) : 0;
  55. char **daemon_argv = NULL;
  56. String8 tmp_8;
  57. if (argc > 0) {
  58. daemon_argv = (char **)malloc((argc+1)*sizeof(char *));
  59. for (int i = 0; i < argc; ++i) {
  60. jstring arg = reinterpret_cast<jstring>(env->GetObjectArrayElement(argv, i));
  61. const jchar *str = env->GetStringCritical(arg, 0);
  62. tmp_8.set(str, env->GetStringLength(arg));
  63. env->ReleaseStringCritical(arg, str);
  64. daemon_argv[i] = strdup(tmp_8.string());
  65. }
  66. daemon_argv[argc] = NULL;
  67. }
  68. int ret = main(argc, daemon_argv);
  69. for (int i = 0; i < argc; i++) free(daemon_argv[i]);
  70. free(daemon_argv);
  71. return ret;
  72. }
  73. /*
  74. * Register several native methods for one class.
  75. */
  76. static int registerNativeMethods(JNIEnv* env)
  77. {
  78. const char *daemonClassPathName = "com/github/shadowsocks/Daemon";
  79. const char *vpnClassPathName = "com/github/shadowsocks/ShadowsocksVpnService";
  80. vpnClazz = env->FindClass(vpnClassPathName);
  81. if (vpnClazz == NULL)
  82. {
  83. LOGE("Native registration unable to find class '%s'", vpnClassPathName);
  84. return JNI_FALSE;
  85. }
  86. newProtectedSocketMethod = env->GetStaticMethodID(vpnClazz, "newProtectedSocket", "()I");
  87. if (newProtectedSocketMethod < 0)
  88. {
  89. LOGE("RegisterNatives failed for newProtectedSocketMethod");
  90. return JNI_FALSE;
  91. }
  92. freeProtectedSocketMethod = env->GetStaticMethodID(vpnClazz, "freeProtectedSocket", "(I)V");
  93. if (freeProtectedSocketMethod < 0)
  94. {
  95. LOGE("RegisterNatives failed for freeProtectedSocketMethod");
  96. return JNI_FALSE;
  97. }
  98. daemonClazz = env->FindClass(daemonClassPathName);
  99. if (daemonClazz == NULL)
  100. {
  101. LOGE("Native registration unable to find class '%s'", daemonClassPathName);
  102. return JNI_FALSE;
  103. }
  104. JNINativeMethod methods[] = {
  105. { "exec", "([Ljava/lang/String;)I",
  106. (void*) Java_com_github_shadowsocks_daemon_exec }
  107. };
  108. if (env->RegisterNatives(daemonClazz, methods, 1) < 0) {
  109. LOGE("RegisterNatives failed for '%s'", daemonClassPathName);
  110. return JNI_FALSE;
  111. }
  112. return JNI_TRUE;
  113. }
  114. jint new_protected_socket()
  115. {
  116. if (newProtectedSocketMethod != NULL)
  117. {
  118. JNIEnv* env = uenv.env;
  119. return env->CallStaticIntMethod(vpnClazz, newProtectedSocketMethod);
  120. }
  121. return -1;
  122. }
  123. void free_protected_socket(jint fd)
  124. {
  125. if (newProtectedSocketMethod != NULL)
  126. {
  127. JNIEnv* env = uenv.env;
  128. env->CallStaticVoidMethod(vpnClazz, freeProtectedSocketMethod, fd);
  129. }
  130. }
  131. jint JNI_OnLoad(JavaVM* vm, void* reserved)
  132. {
  133. uenv.venv = NULL;
  134. jint result = -1;
  135. JNIEnv* env = NULL;
  136. LOGI("JNI_OnLoad");
  137. if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
  138. LOGE("ERROR: GetEnv failed");
  139. goto bail;
  140. }
  141. env = uenv.env;
  142. if (registerNativeMethods(env) != JNI_TRUE) {
  143. LOGE("ERROR: registerNatives failed");
  144. goto bail;
  145. }
  146. result = JNI_VERSION_1_4;
  147. bail:
  148. return result;
  149. }