From a4f9028e08d6e7398a35b81608c4492edf7f467a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 8 Aug 2012 11:54:36 +0200 Subject: [PATCH] CharonVpnService reacts on Intents and properly inits/deinits charon Charon is initialized with every new connection attempt and deinitialized when the service is terminated or it receives an empty Intent (or before starting a new connection). A separate thread is used to handle the connection attempts, this thread acts as main thread for charon. --- .../strongswan/android/logic/CharonVpnService.java | 151 +++++++++++++++++++-- 1 file changed, 140 insertions(+), 11 deletions(-) diff --git a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java index b32f9ae..2f11cf1 100644 --- a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java @@ -1,34 +1,163 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + package org.strongswan.android.logic; +import org.strongswan.android.data.VpnProfile; +import org.strongswan.android.data.VpnProfileDataSource; + import android.content.Intent; import android.net.VpnService; +import android.os.Bundle; +import android.util.Log; -public class CharonVpnService extends VpnService +public class CharonVpnService extends VpnService implements Runnable { + private static final String TAG = CharonVpnService.class.getSimpleName(); + private VpnProfileDataSource mDataSource; + private Thread mConnectionHandler; + private VpnProfile mCurrentProfile; + private VpnProfile mNextProfile; + private volatile boolean mProfileUpdated; + private volatile boolean mTerminate; @Override public int onStartCommand(Intent intent, int flags, int startId) { - // called whenever the service is started with startService - // create our own thread because we are running in the calling processes - // main thread - return super.onStartCommand(intent, flags, startId); + if (intent != null) + { + Bundle bundle = intent.getExtras(); + VpnProfile profile = null; + if (bundle != null) + { + profile = mDataSource.getVpnProfile(bundle.getLong(VpnProfileDataSource.KEY_ID)); + if (profile != null) + { + String password = bundle.getString(VpnProfileDataSource.KEY_PASSWORD); + profile.setPassword(password); + } + } + setNextProfile(profile); + } + return START_NOT_STICKY; } @Override public void onCreate() { - // onCreate is only called once - initializeCharon(); - super.onCreate(); + mDataSource = new VpnProfileDataSource(this); + mDataSource.open(); + /* use a separate thread as main thread for charon */ + mConnectionHandler = new Thread(this); + mConnectionHandler.start(); + } + + @Override + public void onRevoke() + { /* the system revoked the rights grated with the initial prepare() call. + * called when the user clicks disconnect in the system's VPN dialog */ + setNextProfile(null); } @Override public void onDestroy() { - // called once the service is to be destroyed - deinitializeCharon(); - super.onDestroy(); + mTerminate = true; + setNextProfile(null); + try + { + mConnectionHandler.join(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + mDataSource.close(); + } + + /** + * Set the profile that is to be initiated next. Notify the handler thread. + * + * @param profile the profile to initiate + */ + private void setNextProfile(VpnProfile profile) + { + synchronized (this) + { + this.mNextProfile = profile; + mProfileUpdated = true; + notifyAll(); + } + } + + @Override + public void run() + { + while (true) + { + synchronized (this) + { + try + { + while (!mProfileUpdated) + { + wait(); + } + + mProfileUpdated = false; + stopCurrentConnection(); + if (mNextProfile == null) + { + if (mTerminate) + { + break; + } + } + else + { + mCurrentProfile = mNextProfile; + mNextProfile = null; + + initializeCharon(); + Log.i(TAG, "charon started"); + } + } + catch (InterruptedException ex) + { + stopCurrentConnection(); + } + } + } + } + + /** + * Stop any existing connection by deinitializing charon. + */ + private void stopCurrentConnection() + { + synchronized (this) + { + if (mCurrentProfile != null) + { + deinitializeCharon(); + Log.i(TAG, "charon stopped"); + mCurrentProfile = null; + } + } } /** -- 2.7.4