android: Add a custom kernel-net implementation to replace kernel-netlink
[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 JNI_METHOD(NetworkManager, networkChanged, void,
56 bool disconnected)
57 {
58 private_network_manager_t *nm;
59
60 nm = (private_network_manager_t*)charonservice->get_network_manager(
61 charonservice);
62 nm->mutex->lock(nm->mutex);
63 if (nm->connectivity_cb.cb)
64 {
65 nm->connectivity_cb.cb(nm->connectivity_cb.data, disconnected);
66 }
67 nm->mutex->unlock(nm->mutex);
68 }
69
70 METHOD(network_manager_t, add_connectivity_cb, void,
71 private_network_manager_t *this, connectivity_cb_t cb, void *data)
72 {
73 this->mutex->lock(this->mutex);
74 if (!this->connectivity_cb.cb)
75 {
76 JNIEnv *env;
77 jmethodID method_id;
78
79 androidjni_attach_thread(&env);
80 method_id = (*env)->GetMethodID(env, this->cls, "Register", "()V");
81 if (!method_id)
82 {
83 androidjni_exception_occurred(env);
84 }
85 else
86 {
87 (*env)->CallVoidMethod(env, this->obj, method_id);
88 if (!androidjni_exception_occurred(env))
89 {
90 this->connectivity_cb.cb = cb;
91 this->connectivity_cb.data = data;
92 }
93 androidjni_detach_thread();
94 }
95 }
96 this->mutex->unlock(this->mutex);
97 }
98
99 /**
100 * Unregister the NetworkManager via JNI.
101 *
102 * this->mutex has to be locked
103 */
104 static void unregister_network_manager(private_network_manager_t *this)
105 {
106 JNIEnv *env;
107 jmethodID method_id;
108
109 androidjni_attach_thread(&env);
110 method_id = (*env)->GetMethodID(env, this->cls, "Unregister", "()V");
111 if (!method_id)
112 {
113 androidjni_exception_occurred(env);
114 }
115 else
116 {
117 (*env)->CallVoidMethod(env, this->obj, method_id);
118 androidjni_exception_occurred(env);
119 }
120 androidjni_detach_thread();
121 }
122
123 METHOD(network_manager_t, remove_connectivity_cb, void,
124 private_network_manager_t *this, connectivity_cb_t cb)
125 {
126 this->mutex->lock(this->mutex);
127 if (this->connectivity_cb.cb == cb)
128 {
129 this->connectivity_cb.cb = NULL;
130 unregister_network_manager(this);
131 }
132 this->mutex->unlock(this->mutex);
133 }
134
135 METHOD(network_manager_t, destroy, void,
136 private_network_manager_t *this)
137 {
138 JNIEnv *env;
139
140 this->mutex->lock(this->mutex);
141 if (this->connectivity_cb.cb)
142 {
143 this->connectivity_cb.cb = NULL;
144 unregister_network_manager(this);
145 }
146 this->mutex->unlock(this->mutex);
147
148 androidjni_attach_thread(&env);
149 if (this->obj)
150 {
151 (*env)->DeleteGlobalRef(env, this->obj);
152 }
153 if (this->cls)
154 {
155 (*env)->DeleteGlobalRef(env, this->cls);
156 }
157 androidjni_detach_thread();
158 this->mutex->destroy(this->mutex);
159 free(this);
160 }
161
162 /*
163 * Described in header.
164 */
165 network_manager_t *network_manager_create(jobject context)
166 {
167 private_network_manager_t *this;
168 JNIEnv *env;
169 jmethodID method_id;
170 jobject obj;
171 jclass cls;
172
173 INIT(this,
174 .public = {
175 .add_connectivity_cb = _add_connectivity_cb,
176 .remove_connectivity_cb = _remove_connectivity_cb,
177 .destroy = _destroy,
178 },
179 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
180 );
181
182 androidjni_attach_thread(&env);
183 cls = (*env)->FindClass(env, JNI_PACKAGE_STRING "/NetworkManager");
184 if (!cls)
185 {
186 goto failed;
187 }
188 this->cls = (*env)->NewGlobalRef(env, cls);
189 method_id = (*env)->GetMethodID(env, cls, "<init>",
190 "(Landroid/content/Context;)V");
191 if (!method_id)
192 {
193 goto failed;
194 }
195 obj = (*env)->NewObject(env, cls, method_id, context);
196 if (!obj)
197 {
198 goto failed;
199 }
200 this->obj = (*env)->NewGlobalRef(env, obj);
201 androidjni_detach_thread();
202 return &this->public;
203
204 failed:
205 DBG1(DBG_KNL, "failed to build NetworkManager object");
206 androidjni_exception_occurred(env);
207 androidjni_detach_thread();
208 destroy(this);
209 return NULL;
210 };