Merge branch 'pt-tls'
[strongswan.git] / src / frontends / android / jni / libandroidbridge / kernel / network_manager.c
1 /*
2 * Copyright (C) 2012-2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #include "network_manager.h"
16
17 #include "../android_jni.h"
18 #include "../charonservice.h"
19 #include <utils/debug.h>
20 #include <threading/mutex.h>
21
22 typedef struct private_network_manager_t private_network_manager_t;
23
24 struct private_network_manager_t {
25
26 /**
27 * Public interface
28 */
29 network_manager_t public;
30
31 /**
32 * Reference to NetworkManager object
33 */
34 jobject obj;
35
36 /**
37 * Java class for NetworkManager
38 */
39 jclass cls;
40
41 /**
42 * Registered callback
43 */
44 struct {
45 connectivity_cb_t cb;
46 void *data;
47 } connectivity_cb;
48
49 /**
50 * Mutex to access callback
51 */
52 mutex_t *mutex;
53 };
54
55 METHOD(network_manager_t, get_local_address, host_t*,
56 private_network_manager_t *this, bool ipv4)
57 {
58 JNIEnv *env;
59 jmethodID method_id;
60 jstring jaddr;
61 char *addr;
62 host_t *host;
63
64 androidjni_attach_thread(&env);
65 method_id = (*env)->GetMethodID(env, this->cls, "getLocalAddress",
66 "(Z)Ljava/lang/String;");
67 if (!method_id)
68 {
69 goto failed;
70 }
71 jaddr = (*env)->CallObjectMethod(env, this->obj, method_id, ipv4);
72 if (!jaddr || androidjni_exception_occurred(env))
73 {
74 goto failed;
75 }
76 addr = androidjni_convert_jstring(env, jaddr);
77 androidjni_detach_thread();
78 host = host_create_from_string(addr, 0);
79 free(addr);
80 return host;
81
82 failed:
83 androidjni_exception_occurred(env);
84 androidjni_detach_thread();
85 return NULL;
86 }
87
88 METHOD(network_manager_t, get_interface, bool,
89 private_network_manager_t *this, host_t *ip, char **name)
90 {
91 JNIEnv *env;
92 jmethodID method_id;
93 jbyteArray jaddr;
94 jstring jinterface;
95
96 if (ip->is_anyaddr(ip))
97 {
98 return FALSE;
99 }
100
101 androidjni_attach_thread(&env);
102
103 method_id = (*env)->GetMethodID(env, this->cls, "getInterface",
104 "([B)Ljava/lang/String;");
105 if (!method_id)
106 {
107 goto failed;
108 }
109 jaddr = byte_array_from_chunk(env, ip->get_address(ip));
110 jinterface = (*env)->CallObjectMethod(env, this->obj, method_id, jaddr);
111 if (!jinterface || androidjni_exception_occurred(env))
112 {
113 goto failed;
114 }
115 if (name)
116 {
117 *name = androidjni_convert_jstring(env, jinterface);
118 }
119 androidjni_detach_thread();
120 return TRUE;
121
122 failed:
123 androidjni_exception_occurred(env);
124 androidjni_detach_thread();
125 return FALSE;
126 }
127
128 JNI_METHOD(NetworkManager, networkChanged, void,
129 bool disconnected)
130 {
131 private_network_manager_t *nm;
132
133 nm = (private_network_manager_t*)charonservice->get_network_manager(
134 charonservice);
135 nm->mutex->lock(nm->mutex);
136 if (nm->connectivity_cb.cb)
137 {
138 nm->connectivity_cb.cb(nm->connectivity_cb.data, disconnected);
139 }
140 nm->mutex->unlock(nm->mutex);
141 }
142
143 METHOD(network_manager_t, add_connectivity_cb, void,
144 private_network_manager_t *this, connectivity_cb_t cb, void *data)
145 {
146 this->mutex->lock(this->mutex);
147 if (!this->connectivity_cb.cb)
148 {
149 JNIEnv *env;
150 jmethodID method_id;
151
152 androidjni_attach_thread(&env);
153 method_id = (*env)->GetMethodID(env, this->cls, "Register", "()V");
154 if (!method_id)
155 {
156 androidjni_exception_occurred(env);
157 }
158 else
159 {
160 (*env)->CallVoidMethod(env, this->obj, method_id);
161 if (!androidjni_exception_occurred(env))
162 {
163 this->connectivity_cb.cb = cb;
164 this->connectivity_cb.data = data;
165 }
166 androidjni_detach_thread();
167 }
168 }
169 this->mutex->unlock(this->mutex);
170 }
171
172 /**
173 * Unregister the NetworkManager via JNI.
174 *
175 * this->mutex has to be locked
176 */
177 static void unregister_network_manager(private_network_manager_t *this)
178 {
179 JNIEnv *env;
180 jmethodID method_id;
181
182 androidjni_attach_thread(&env);
183 method_id = (*env)->GetMethodID(env, this->cls, "Unregister", "()V");
184 if (!method_id)
185 {
186 androidjni_exception_occurred(env);
187 }
188 else
189 {
190 (*env)->CallVoidMethod(env, this->obj, method_id);
191 androidjni_exception_occurred(env);
192 }
193 androidjni_detach_thread();
194 }
195
196 METHOD(network_manager_t, remove_connectivity_cb, void,
197 private_network_manager_t *this, connectivity_cb_t cb)
198 {
199 this->mutex->lock(this->mutex);
200 if (this->connectivity_cb.cb == cb)
201 {
202 this->connectivity_cb.cb = NULL;
203 unregister_network_manager(this);
204 }
205 this->mutex->unlock(this->mutex);
206 }
207
208 METHOD(network_manager_t, destroy, void,
209 private_network_manager_t *this)
210 {
211 JNIEnv *env;
212
213 this->mutex->lock(this->mutex);
214 if (this->connectivity_cb.cb)
215 {
216 this->connectivity_cb.cb = NULL;
217 unregister_network_manager(this);
218 }
219 this->mutex->unlock(this->mutex);
220
221 androidjni_attach_thread(&env);
222 if (this->obj)
223 {
224 (*env)->DeleteGlobalRef(env, this->obj);
225 }
226 if (this->cls)
227 {
228 (*env)->DeleteGlobalRef(env, this->cls);
229 }
230 androidjni_detach_thread();
231 this->mutex->destroy(this->mutex);
232 free(this);
233 }
234
235 /*
236 * Described in header.
237 */
238 network_manager_t *network_manager_create(jobject context)
239 {
240 private_network_manager_t *this;
241 JNIEnv *env;
242 jmethodID method_id;
243 jobject obj;
244 jclass cls;
245
246 INIT(this,
247 .public = {
248 .get_local_address = _get_local_address,
249 .get_interface = _get_interface,
250 .add_connectivity_cb = _add_connectivity_cb,
251 .remove_connectivity_cb = _remove_connectivity_cb,
252 .destroy = _destroy,
253 },
254 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
255 );
256
257 androidjni_attach_thread(&env);
258 cls = (*env)->FindClass(env, JNI_PACKAGE_STRING "/NetworkManager");
259 if (!cls)
260 {
261 goto failed;
262 }
263 this->cls = (*env)->NewGlobalRef(env, cls);
264 method_id = (*env)->GetMethodID(env, cls, "<init>",
265 "(Landroid/content/Context;)V");
266 if (!method_id)
267 {
268 goto failed;
269 }
270 obj = (*env)->NewObject(env, cls, method_id, context);
271 if (!obj)
272 {
273 goto failed;
274 }
275 this->obj = (*env)->NewGlobalRef(env, obj);
276 androidjni_detach_thread();
277 return &this->public;
278
279 failed:
280 DBG1(DBG_KNL, "failed to build NetworkManager object");
281 androidjni_exception_occurred(env);
282 androidjni_detach_thread();
283 destroy(this);
284 return NULL;
285 };