+/*
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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;
+ }
+ }
}
/**