summaryrefslogtreecommitdiffhomepage
path: root/tunnel/tools/libwg-go/jni.c
blob: 3660e96a67a1d9fc0a6ef6b6bd284067c3ea9f7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* SPDX-License-Identifier: Apache-2.0
 *
 * Copyright © 2017-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
 */

#include <assert.h>
#include <jni.h>
#include <stdlib.h>
#include <string.h>
#include <android/log.h>

#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");
}