]>
Commit | Line | Data |
---|---|---|
a4f9028e TB |
1 | /* |
2 | * Copyright (C) 2012 Tobias Brunner | |
3 | * Copyright (C) 2012 Giuliano Grassi | |
4 | * Copyright (C) 2012 Ralf Sager | |
5 | * Hochschule fuer Technik Rapperswil | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | * for more details. | |
16 | */ | |
17 | ||
8bf30276 | 18 | package org.strongswan.android.logic; |
4a208143 | 19 | |
a4f9028e TB |
20 | import org.strongswan.android.data.VpnProfile; |
21 | import org.strongswan.android.data.VpnProfileDataSource; | |
03de55ad TB |
22 | import org.strongswan.android.logic.VpnStateService.ErrorState; |
23 | import org.strongswan.android.logic.VpnStateService.State; | |
a4f9028e | 24 | |
03de55ad TB |
25 | import android.app.Service; |
26 | import android.content.ComponentName; | |
4a208143 | 27 | import android.content.Intent; |
03de55ad | 28 | import android.content.ServiceConnection; |
4a208143 | 29 | import android.net.VpnService; |
a4f9028e | 30 | import android.os.Bundle; |
03de55ad | 31 | import android.os.IBinder; |
a4f9028e | 32 | import android.util.Log; |
4a208143 | 33 | |
a4f9028e | 34 | public class CharonVpnService extends VpnService implements Runnable |
a4057603 | 35 | { |
a4f9028e TB |
36 | private static final String TAG = CharonVpnService.class.getSimpleName(); |
37 | private VpnProfileDataSource mDataSource; | |
38 | private Thread mConnectionHandler; | |
39 | private VpnProfile mCurrentProfile; | |
40 | private VpnProfile mNextProfile; | |
41 | private volatile boolean mProfileUpdated; | |
42 | private volatile boolean mTerminate; | |
03de55ad TB |
43 | private VpnStateService mService; |
44 | private final Object mServiceLock = new Object(); | |
45 | private final ServiceConnection mServiceConnection = new ServiceConnection() { | |
46 | @Override | |
47 | public void onServiceDisconnected(ComponentName name) | |
48 | { /* since the service is local this is theoretically only called when the process is terminated */ | |
49 | synchronized (mServiceLock) | |
50 | { | |
51 | mService = null; | |
52 | } | |
53 | } | |
54 | ||
55 | @Override | |
56 | public void onServiceConnected(ComponentName name, IBinder service) | |
57 | { | |
58 | synchronized (mServiceLock) | |
59 | { | |
60 | mService = ((VpnStateService.LocalBinder)service).getService(); | |
61 | } | |
62 | /* we are now ready to start the handler thread */ | |
63 | mConnectionHandler.start(); | |
64 | } | |
65 | }; | |
4a208143 TB |
66 | |
67 | @Override | |
a4057603 TB |
68 | public int onStartCommand(Intent intent, int flags, int startId) |
69 | { | |
a4f9028e TB |
70 | if (intent != null) |
71 | { | |
72 | Bundle bundle = intent.getExtras(); | |
73 | VpnProfile profile = null; | |
74 | if (bundle != null) | |
75 | { | |
76 | profile = mDataSource.getVpnProfile(bundle.getLong(VpnProfileDataSource.KEY_ID)); | |
77 | if (profile != null) | |
78 | { | |
79 | String password = bundle.getString(VpnProfileDataSource.KEY_PASSWORD); | |
80 | profile.setPassword(password); | |
81 | } | |
82 | } | |
83 | setNextProfile(profile); | |
84 | } | |
85 | return START_NOT_STICKY; | |
4a208143 TB |
86 | } |
87 | ||
88 | @Override | |
a4057603 TB |
89 | public void onCreate() |
90 | { | |
a4f9028e TB |
91 | mDataSource = new VpnProfileDataSource(this); |
92 | mDataSource.open(); | |
93 | /* use a separate thread as main thread for charon */ | |
94 | mConnectionHandler = new Thread(this); | |
03de55ad TB |
95 | /* the thread is started when the service is bound */ |
96 | bindService(new Intent(this, VpnStateService.class), | |
97 | mServiceConnection, Service.BIND_AUTO_CREATE); | |
a4f9028e TB |
98 | } |
99 | ||
100 | @Override | |
101 | public void onRevoke() | |
102 | { /* the system revoked the rights grated with the initial prepare() call. | |
103 | * called when the user clicks disconnect in the system's VPN dialog */ | |
104 | setNextProfile(null); | |
4a208143 TB |
105 | } |
106 | ||
107 | @Override | |
a4057603 TB |
108 | public void onDestroy() |
109 | { | |
a4f9028e TB |
110 | mTerminate = true; |
111 | setNextProfile(null); | |
112 | try | |
113 | { | |
114 | mConnectionHandler.join(); | |
115 | } | |
116 | catch (InterruptedException e) | |
117 | { | |
118 | e.printStackTrace(); | |
119 | } | |
03de55ad TB |
120 | if (mService != null) |
121 | { | |
122 | unbindService(mServiceConnection); | |
123 | } | |
a4f9028e TB |
124 | mDataSource.close(); |
125 | } | |
126 | ||
127 | /** | |
128 | * Set the profile that is to be initiated next. Notify the handler thread. | |
129 | * | |
130 | * @param profile the profile to initiate | |
131 | */ | |
132 | private void setNextProfile(VpnProfile profile) | |
133 | { | |
134 | synchronized (this) | |
135 | { | |
136 | this.mNextProfile = profile; | |
137 | mProfileUpdated = true; | |
138 | notifyAll(); | |
139 | } | |
140 | } | |
141 | ||
142 | @Override | |
143 | public void run() | |
144 | { | |
145 | while (true) | |
146 | { | |
147 | synchronized (this) | |
148 | { | |
149 | try | |
150 | { | |
151 | while (!mProfileUpdated) | |
152 | { | |
153 | wait(); | |
154 | } | |
155 | ||
156 | mProfileUpdated = false; | |
157 | stopCurrentConnection(); | |
158 | if (mNextProfile == null) | |
159 | { | |
03de55ad TB |
160 | setProfile(null); |
161 | setState(State.DISABLED); | |
a4f9028e TB |
162 | if (mTerminate) |
163 | { | |
164 | break; | |
165 | } | |
166 | } | |
167 | else | |
168 | { | |
169 | mCurrentProfile = mNextProfile; | |
170 | mNextProfile = null; | |
171 | ||
03de55ad TB |
172 | setProfile(mCurrentProfile); |
173 | setError(ErrorState.NO_ERROR); | |
174 | setState(State.CONNECTING); | |
175 | ||
a4f9028e TB |
176 | initializeCharon(); |
177 | Log.i(TAG, "charon started"); | |
178 | } | |
179 | } | |
180 | catch (InterruptedException ex) | |
181 | { | |
182 | stopCurrentConnection(); | |
03de55ad | 183 | setState(State.DISABLED); |
a4f9028e TB |
184 | } |
185 | } | |
186 | } | |
187 | } | |
188 | ||
189 | /** | |
190 | * Stop any existing connection by deinitializing charon. | |
191 | */ | |
192 | private void stopCurrentConnection() | |
193 | { | |
194 | synchronized (this) | |
195 | { | |
196 | if (mCurrentProfile != null) | |
197 | { | |
03de55ad | 198 | setState(State.DISCONNECTING); |
a4f9028e TB |
199 | deinitializeCharon(); |
200 | Log.i(TAG, "charon stopped"); | |
201 | mCurrentProfile = null; | |
202 | } | |
203 | } | |
4a208143 TB |
204 | } |
205 | ||
03de55ad TB |
206 | /** |
207 | * Update the VPN profile on the state service. Called by the handler thread. | |
208 | * | |
209 | * @param profile currently active VPN profile | |
210 | */ | |
211 | private void setProfile(VpnProfile profile) | |
212 | { | |
213 | synchronized (mServiceLock) | |
214 | { | |
215 | if (mService != null) | |
216 | { | |
217 | mService.setProfile(profile); | |
218 | } | |
219 | } | |
220 | } | |
221 | ||
222 | /** | |
223 | * Update the current VPN state on the state service. Called by the handler | |
224 | * thread and any of charon's threads. | |
225 | * | |
226 | * @param state current state | |
227 | */ | |
228 | private void setState(State state) | |
229 | { | |
230 | synchronized (mServiceLock) | |
231 | { | |
232 | if (mService != null) | |
233 | { | |
234 | mService.setState(state); | |
235 | } | |
236 | } | |
237 | } | |
238 | ||
239 | /** | |
240 | * Set an error on the state service. Called by the handler thread and any | |
241 | * of charon's threads. | |
242 | * | |
243 | * @param error error state | |
244 | */ | |
245 | private void setError(ErrorState error) | |
246 | { | |
247 | synchronized (mServiceLock) | |
248 | { | |
249 | if (mService != null) | |
250 | { | |
251 | mService.setError(error); | |
252 | } | |
253 | } | |
254 | } | |
255 | ||
4a208143 TB |
256 | /** |
257 | * Initialization of charon, provided by libandroidbridge.so | |
258 | */ | |
259 | public native void initializeCharon(); | |
260 | ||
261 | /** | |
262 | * Deinitialize charon, provided by libandroidbridge.so | |
263 | */ | |
264 | public native void deinitializeCharon(); | |
265 | ||
266 | /* | |
267 | * The libraries are extracted to /data/data/org.strongswan.android/... | |
268 | * during installation. | |
269 | */ | |
a4057603 TB |
270 | static |
271 | { | |
4a208143 TB |
272 | System.loadLibrary("crypto"); |
273 | System.loadLibrary("strongswan"); | |
274 | System.loadLibrary("hydra"); | |
275 | System.loadLibrary("charon"); | |
06ed785e | 276 | System.loadLibrary("ipsec"); |
4a208143 TB |
277 | System.loadLibrary("androidbridge"); |
278 | } | |
279 | } |