/* SPDX-License-Identifier: Apache-2.0 * * Copyright © 2017-2021 Jason A. Donenfeld . All Rights Reserved. */ #include #include #include #include #include #define TAG "WireGuard/GoBackend" struct go_string { const char *str; long n; }; extern int wgTurnOn(struct go_string ifname, int tun_fd, struct go_string settings, void *eventHandler); extern int wgTurnOnDhcp(struct go_string ifname, struct go_string lladdr, struct go_string settings, void *eventHandler); extern void wgSetFd(int handle, int tun_fd); extern void *wgTurnOff(int handle); extern int wgGetSocketV4(int handle); extern int wgGetSocketV6(int handle); extern char *wgGetConfig(int handle); extern char *wgVersion(); extern void wgOnEvent(void *eventHandler, const char *event); static JavaVM *gVm; static jclass gEventHandlerClass; static jmethodID gOnEventMethod; JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv* env; char buf[128]; __android_log_write(ANDROID_LOG_ERROR, TAG, "JNI_OnLoad"); gVm = vm; if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) { __android_log_write(ANDROID_LOG_ERROR, TAG, "GetEnv error"); return JNI_ERR; } sprintf(buf, "GetEnv FindClass %p", (*env)->FindClass); __android_log_write(ANDROID_LOG_ERROR, TAG, buf); gEventHandlerClass = (*env)->FindClass(env, "com/wireguard/android/backend/EventHandler"); sprintf(buf, "gEventHandlerClass %p", gEventHandlerClass); __android_log_write(ANDROID_LOG_ERROR, TAG, buf); gOnEventMethod = (*env)->GetMethodID(env, gEventHandlerClass, "onEvent", "(Ljava/lang/String;)V"); sprintf(buf, "gOnEventMethod %p", gOnEventMethod); __android_log_write(ANDROID_LOG_ERROR, TAG, buf); //assert(gOnEventMethod); return JNI_VERSION_1_6; } JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOn(JNIEnv *env, jclass c, jstring ifname, jint tun_fd, jstring settings, jobject eventHandler) { const char *ifname_str = (*env)->GetStringUTFChars(env, ifname, 0); size_t ifname_len = (*env)->GetStringUTFLength(env, ifname); const char *settings_str = (*env)->GetStringUTFChars(env, settings, 0); size_t settings_len = (*env)->GetStringUTFLength(env, settings); jobject event_handler = (*env)->NewGlobalRef(env, eventHandler); int ret = wgTurnOn((struct go_string){ .str = ifname_str, .n = ifname_len }, tun_fd, (struct go_string){ .str = settings_str, .n = settings_len }, event_handler); (*env)->ReleaseStringUTFChars(env, ifname, ifname_str); (*env)->ReleaseStringUTFChars(env, settings, settings_str); return ret; } JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOnDhcp(JNIEnv *env, jclass c, jstring ifname, jstring lladdr, jstring settings, jobject eventHandler) { const char *ifname_str = (*env)->GetStringUTFChars(env, ifname, 0); size_t ifname_len = (*env)->GetStringUTFLength(env, ifname); const char *lladdr_str = (*env)->GetStringUTFChars(env, lladdr, 0); size_t lladdr_len = (*env)->GetStringUTFLength(env, lladdr); const char *settings_str = (*env)->GetStringUTFChars(env, settings, 0); size_t settings_len = (*env)->GetStringUTFLength(env, settings); jobject event_handler = (*env)->NewGlobalRef(env, eventHandler); int ret = wgTurnOnDhcp((struct go_string){ .str = ifname_str, .n = ifname_len }, (struct go_string){ .str = lladdr_str, .n = lladdr_len }, (struct go_string){ .str = settings_str, .n = settings_len }, event_handler); (*env)->ReleaseStringUTFChars(env, ifname, ifname_str); (*env)->ReleaseStringUTFChars(env, lladdr, lladdr_str); (*env)->ReleaseStringUTFChars(env, settings, settings_str); return ret; } JNIEXPORT void JNICALL Java_com_wireguard_android_backend_GoBackend_wgSetFd(JNIEnv *env, jclass c, jint handle, jint tun_fd) { wgSetFd(handle, tun_fd); } JNIEXPORT void JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOff(JNIEnv *env, jclass c, jint handle) { jobject event_handler = wgTurnOff(handle); if (event_handler) (*env)->DeleteGlobalRef(env, event_handler); } JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetSocketV4(JNIEnv *env, jclass c, jint handle) { return wgGetSocketV4(handle); } JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetSocketV6(JNIEnv *env, jclass c, jint handle) { return wgGetSocketV6(handle); } JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetConfig(JNIEnv *env, jclass c, jint handle) { jstring ret; char *config = wgGetConfig(handle); if (!config) return NULL; ret = (*env)->NewStringUTF(env, config); free(config); return ret; } JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgVersion(JNIEnv *env, jclass c) { jstring ret; char *version = wgVersion(); if (!version) return NULL; ret = (*env)->NewStringUTF(env, version); free(version); return ret; } void wgOnEvent(void *eventHandler, const char *event) { JavaVMAttachArgs attachArgs = { JNI_VERSION_1_6, NULL, NULL }; jobject jEventHandler = eventHandler; JNIEnv *env; char buf[128]; __android_log_write(ANDROID_LOG_ERROR, TAG, "wgOnEvent enter 2"); jint rs = (*gVm)->AttachCurrentThread(gVm, &env, &attachArgs); sprintf(buf, "AttachCurrentThread %i %p", rs, env); __android_log_write(ANDROID_LOG_ERROR, TAG, buf); assert (rs == JNI_OK); jstring jevent = (*env)->NewStringUTF(env, event); sprintf(buf, "NewStringUTF %p", jevent); __android_log_write(ANDROID_LOG_ERROR, TAG, buf); //free(event); sprintf(buf, "CallVoidMethod %p %p %p %p", env, jEventHandler, gOnEventMethod, jevent); __android_log_write(ANDROID_LOG_ERROR, TAG, buf); (*env)->CallVoidMethod(env, jEventHandler, gOnEventMethod, jevent); /* sprintf(buf, "CallVoidMethod"); */ /* __android_log_write(ANDROID_LOG_ERROR, TAG, buf); */ // TODO free jevent? __android_log_write(ANDROID_LOG_ERROR, TAG, "wgOnEvent end"); }