android: Add state of IMC to VpnStateService and update it via JNI

This commit is contained in:
Tobias Brunner
2013-07-08 18:49:28 +02:00
parent d087f080f0
commit dc52cfab73
6 changed files with 203 additions and 3 deletions
@@ -18,6 +18,7 @@
#include "imc_android_state.h"
#include "../android_jni.h"
#include "../charonservice.h"
#include <tnc/tnc.h>
#include <libpts.h>
@@ -98,6 +99,29 @@ static TNC_Result tnc_imc_initialize(TNC_IMCID imc_id,
return TNC_RESULT_SUCCESS;
}
/**
* Update the state in the GUI.
*/
static void update_imc_state(TNC_ConnectionState state)
{
android_imc_state_t imc_state = ANDROID_IMC_STATE_UNKNOWN;
switch (state)
{ /* map connection states to the values used by the GUI */
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
imc_state = ANDROID_IMC_STATE_ALLOW;
break;
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
imc_state = ANDROID_IMC_STATE_ISOLATE;
break;
case TNC_CONNECTION_STATE_ACCESS_NONE:
imc_state = ANDROID_IMC_STATE_BLOCK;
break;
}
charonservice->update_imc_state(charonservice, imc_state);
}
/**
* see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
@@ -128,6 +152,11 @@ static TNC_Result tnc_imc_notifyconnectionchange(TNC_IMCID imc_id,
return TNC_RESULT_SUCCESS;
case TNC_CONNECTION_STATE_DELETE:
return imc_android->delete_state(imc_android, connection_id);
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
case TNC_CONNECTION_STATE_ACCESS_NONE:
update_imc_state(new_state);
/* fall-through */
default:
return imc_android->change_state(imc_android, connection_id,
new_state, NULL);
@@ -162,6 +162,30 @@ failed:
return success;
}
METHOD(charonservice_t, update_imc_state, bool,
private_charonservice_t *this, android_imc_state_t state)
{
JNIEnv *env;
jmethodID method_id;
bool success = FALSE;
androidjni_attach_thread(&env);
method_id = (*env)->GetMethodID(env, android_charonvpnservice_class,
"updateImcState", "(I)V");
if (!method_id)
{
goto failed;
}
(*env)->CallVoidMethod(env, this->vpn_service, method_id, (jint)state);
success = !androidjni_exception_occurred(env);
failed:
androidjni_exception_occurred(env);
androidjni_detach_thread();
return success;
}
/**
* Bypass a single socket
*/
@@ -466,6 +490,7 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
INIT(this,
.public = {
.update_status = _update_status,
.update_imc_state = _update_imc_state,
.bypass_socket = _bypass_socket,
.get_trusted_certificates = _get_trusted_certificates,
.get_user_certificate = _get_user_certificate,
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil
@@ -41,6 +41,7 @@
#include <collections/linked_list.h>
typedef enum android_vpn_state_t android_vpn_state_t;
typedef enum android_imc_state_t android_imc_state_t;
typedef struct charonservice_t charonservice_t;
/**
@@ -56,6 +57,16 @@ enum android_vpn_state_t {
CHARONSERVICE_GENERIC_ERROR,
};
/**
* Final IMC state as defined in ImcState.java
*/
enum android_imc_state_t {
ANDROID_IMC_STATE_UNKNOWN = 0,
ANDROID_IMC_STATE_ALLOW = 1,
ANDROID_IMC_STATE_BLOCK = 2,
ANDROID_IMC_STATE_ISOLATE = 3,
};
/**
* Public interface of charonservice.
*
@@ -71,6 +82,14 @@ struct charonservice_t {
*/
bool (*update_status)(charonservice_t *this, android_vpn_state_t code);
/**
* Update final IMC state in the Java domain (UI)
*
* @param state IMC state
* @return TRUE on success
*/
bool (*update_imc_state)(charonservice_t *this, android_imc_state_t state);
/**
* Install a bypass policy for the given socket using the protect() Method
* of the Android VpnService interface.
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil
@@ -27,6 +27,7 @@ import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.data.VpnProfileDataSource;
import org.strongswan.android.logic.VpnStateService.ErrorState;
import org.strongswan.android.logic.VpnStateService.State;
import org.strongswan.android.logic.imc.ImcState;
import org.strongswan.android.ui.MainActivity;
import android.app.PendingIntent;
@@ -208,6 +209,7 @@ public class CharonVpnService extends VpnService implements Runnable
setProfile(mCurrentProfile);
setError(ErrorState.NO_ERROR);
setState(State.CONNECTING);
setImcState(ImcState.UNKNOWN);
mIsDisconnecting = false;
BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName());
@@ -296,6 +298,23 @@ public class CharonVpnService extends VpnService implements Runnable
}
}
/**
* Set the IMC state on the state service. Called by the handler thread and
* any of charon's threads.
*
* @param state IMC state
*/
private void setImcState(ImcState state)
{
synchronized (mServiceLock)
{
if (mService != null)
{
mService.setImcState(state);
}
}
}
/**
* Set an error on the state service and disconnect the current connection.
* This is not done by calling stopCurrentConnection() above, but instead
@@ -355,6 +374,21 @@ public class CharonVpnService extends VpnService implements Runnable
}
}
/**
* Updates the IMC state of the current connection.
* Called via JNI by different threads (but not concurrently).
*
* @param value new state
*/
public void updateImcState(int value)
{
ImcState state = ImcState.fromValue(value);
if (state != null)
{
setImcState(state);
}
}
/**
* Function called via JNI to generate a list of DER encoded CA certificates
* as byte array.
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012-2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,6 +20,7 @@ import java.util.List;
import java.util.concurrent.Callable;
import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.logic.imc.ImcState;
import android.app.Service;
import android.content.Context;
@@ -36,6 +37,7 @@ public class VpnStateService extends Service
private VpnProfile mProfile;
private State mState = State.DISABLED;
private ErrorState mError = ErrorState.NO_ERROR;
private ImcState mImcState = ImcState.UNKNOWN;
public enum State
{
@@ -146,6 +148,16 @@ public class VpnStateService extends Service
return mError;
}
/**
* Get the current IMC state, if any.
*
* @return imc state
*/
public ImcState getImcState()
{ /* only updated from the main thread so no synchronization needed */
return mImcState;
}
/**
* Disconnect any existing connection and shutdown the daemon, the
* VpnService is not stopped but it is reset so new connections can be
@@ -261,4 +273,27 @@ public class VpnStateService extends Service
}
});
}
/**
* Set the current IMC state and notify all listeners, if changed.
*
* May be called from threads other than the main thread.
*
* @param error error state
*/
public void setImcState(final ImcState state)
{
notifyListeners(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception
{
if (VpnStateService.this.mImcState != state)
{
VpnStateService.this.mImcState = state;
return true;
}
return false;
}
});
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.imc;
public enum ImcState
{
UNKNOWN(0),
ALLOW(1),
BLOCK(2),
ISOLATE(3);
private final int mValue;
private ImcState(int value)
{
mValue = value;
}
/**
* Get the numeric value of the IMC state.
* @return numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Get the enum entry from a numeric value, if defined
*
* @param value numeric value
* @return the enum entry or null
*/
public static ImcState fromValue(int value)
{
for (ImcState state : ImcState.values())
{
if (state.mValue == value)
{
return state;
}
}
return null;
}
}