CharonVpnService reacts on Intents and properly inits/deinits charon
[strongswan.git] / src / frontends / android / src / org / strongswan / android / logic / CharonVpnService.java
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
18 package org.strongswan.android.logic;
19
20 import org.strongswan.android.data.VpnProfile;
21 import org.strongswan.android.data.VpnProfileDataSource;
22
23 import android.content.Intent;
24 import android.net.VpnService;
25 import android.os.Bundle;
26 import android.util.Log;
27
28 public class CharonVpnService extends VpnService implements Runnable
29 {
30 private static final String TAG = CharonVpnService.class.getSimpleName();
31 private VpnProfileDataSource mDataSource;
32 private Thread mConnectionHandler;
33 private VpnProfile mCurrentProfile;
34 private VpnProfile mNextProfile;
35 private volatile boolean mProfileUpdated;
36 private volatile boolean mTerminate;
37
38 @Override
39 public int onStartCommand(Intent intent, int flags, int startId)
40 {
41 if (intent != null)
42 {
43 Bundle bundle = intent.getExtras();
44 VpnProfile profile = null;
45 if (bundle != null)
46 {
47 profile = mDataSource.getVpnProfile(bundle.getLong(VpnProfileDataSource.KEY_ID));
48 if (profile != null)
49 {
50 String password = bundle.getString(VpnProfileDataSource.KEY_PASSWORD);
51 profile.setPassword(password);
52 }
53 }
54 setNextProfile(profile);
55 }
56 return START_NOT_STICKY;
57 }
58
59 @Override
60 public void onCreate()
61 {
62 mDataSource = new VpnProfileDataSource(this);
63 mDataSource.open();
64 /* use a separate thread as main thread for charon */
65 mConnectionHandler = new Thread(this);
66 mConnectionHandler.start();
67 }
68
69 @Override
70 public void onRevoke()
71 { /* the system revoked the rights grated with the initial prepare() call.
72 * called when the user clicks disconnect in the system's VPN dialog */
73 setNextProfile(null);
74 }
75
76 @Override
77 public void onDestroy()
78 {
79 mTerminate = true;
80 setNextProfile(null);
81 try
82 {
83 mConnectionHandler.join();
84 }
85 catch (InterruptedException e)
86 {
87 e.printStackTrace();
88 }
89 mDataSource.close();
90 }
91
92 /**
93 * Set the profile that is to be initiated next. Notify the handler thread.
94 *
95 * @param profile the profile to initiate
96 */
97 private void setNextProfile(VpnProfile profile)
98 {
99 synchronized (this)
100 {
101 this.mNextProfile = profile;
102 mProfileUpdated = true;
103 notifyAll();
104 }
105 }
106
107 @Override
108 public void run()
109 {
110 while (true)
111 {
112 synchronized (this)
113 {
114 try
115 {
116 while (!mProfileUpdated)
117 {
118 wait();
119 }
120
121 mProfileUpdated = false;
122 stopCurrentConnection();
123 if (mNextProfile == null)
124 {
125 if (mTerminate)
126 {
127 break;
128 }
129 }
130 else
131 {
132 mCurrentProfile = mNextProfile;
133 mNextProfile = null;
134
135 initializeCharon();
136 Log.i(TAG, "charon started");
137 }
138 }
139 catch (InterruptedException ex)
140 {
141 stopCurrentConnection();
142 }
143 }
144 }
145 }
146
147 /**
148 * Stop any existing connection by deinitializing charon.
149 */
150 private void stopCurrentConnection()
151 {
152 synchronized (this)
153 {
154 if (mCurrentProfile != null)
155 {
156 deinitializeCharon();
157 Log.i(TAG, "charon stopped");
158 mCurrentProfile = null;
159 }
160 }
161 }
162
163 /**
164 * Initialization of charon, provided by libandroidbridge.so
165 */
166 public native void initializeCharon();
167
168 /**
169 * Deinitialize charon, provided by libandroidbridge.so
170 */
171 public native void deinitializeCharon();
172
173 /*
174 * The libraries are extracted to /data/data/org.strongswan.android/...
175 * during installation.
176 */
177 static
178 {
179 System.loadLibrary("crypto");
180 System.loadLibrary("strongswan");
181 System.loadLibrary("hydra");
182 System.loadLibrary("charon");
183 System.loadLibrary("ipsec");
184 System.loadLibrary("androidbridge");
185 }
186 }