Native counterpart of VpnService.Builder added, exposed by charonservice
authorTobias Brunner <tobias@strongswan.org>
Wed, 8 Aug 2012 11:48:54 +0000 (13:48 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 13 Aug 2012 09:09:33 +0000 (11:09 +0200)
src/frontends/android/jni/libandroidbridge/Android.mk
src/frontends/android/jni/libandroidbridge/android_jni.c
src/frontends/android/jni/libandroidbridge/android_jni.h
src/frontends/android/jni/libandroidbridge/charonservice.c
src/frontends/android/jni/libandroidbridge/charonservice.h
src/frontends/android/jni/libandroidbridge/vpnservice_builder.c [new file with mode: 0644]
src/frontends/android/jni/libandroidbridge/vpnservice_builder.h [new file with mode: 0644]
src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java

index 9e1e94a..2e484ec 100644 (file)
@@ -8,7 +8,8 @@ backend/android_creds.c backend/android_creds.h \
 backend/android_service.c backend/android_service.h \
 charonservice.c charonservice.h \
 kernel/android_ipsec.c kernel/android_ipsec.h \
-kernel/android_net.c kernel/android_net.h
+kernel/android_net.c kernel/android_net.h \
+vpnservice_builder.c vpnservice_builder.h
 
 # build libandroidbridge -------------------------------------------------------
 
index b5e935a..e7cb14f 100644 (file)
@@ -26,6 +26,7 @@
 static JavaVM *android_jvm;
 
 jclass *android_charonvpnservice_class;
+jclass *android_charonvpnservice_builder_class;
 
 /**
  * Thread-local variable. Only used because of the destructor
@@ -88,6 +89,9 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved)
        android_charonvpnservice_class =
                                (*env)->NewGlobalRef(env, (*env)->FindClass(env,
                                                JNI_PACKAGE_STRING "/CharonVpnService"));
+       android_charonvpnservice_builder_class =
+                               (*env)->NewGlobalRef(env, (*env)->FindClass(env,
+                                               JNI_PACKAGE_STRING "/CharonVpnService$BuilderAdapter"));
 
        return JNI_VERSION_1_6;
 }
index 427c641..39ba56f 100644 (file)
@@ -43,6 +43,7 @@
  * Initialized in JNI_OnLoad()
  */
 extern jclass *android_charonvpnservice_class;
+extern jclass *android_charonvpnservice_builder_class;
 
 /**
  * Attach the current thread to the JVM
index 8d595fe..772a96f 100644 (file)
@@ -57,6 +57,11 @@ struct private_charonservice_t {
        android_service_t *service;
 
        /**
+        * VpnService builder (accessed via JNI)
+        */
+       vpnservice_builder_t *builder;
+
+       /**
         * CharonVpnService reference
         */
        jobject vpn_service;
@@ -201,6 +206,12 @@ failed:
        return NULL;
 }
 
+METHOD(charonservice_t, get_vpnservice_builder, vpnservice_builder_t*,
+       private_charonservice_t *this)
+{
+       return this->builder;
+}
+
 /**
  * Initiate a new connection
  *
@@ -248,7 +259,7 @@ static bool charonservice_register(void *plugin, plugin_feature_t *feature,
 /**
  * Initialize the charonservice object
  */
-static void charonservice_init(JNIEnv *env, jobject service)
+static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
 {
        private_charonservice_t *this;
        static plugin_feature_t features[] = {
@@ -266,8 +277,10 @@ static void charonservice_init(JNIEnv *env, jobject service)
                        .update_status = _update_status,
                        .bypass_socket = _bypass_socket,
                        .get_trusted_certificates = _get_trusted_certificates,
+                       .get_vpnservice_builder = _get_vpnservice_builder,
                },
                .creds = android_creds_create(),
+               .builder = vpnservice_builder_create(builder),
                .vpn_service = (*env)->NewGlobalRef(env, service),
        );
        charonservice = &this->public;
@@ -286,6 +299,7 @@ static void charonservice_deinit(JNIEnv *env)
 {
        private_charonservice_t *this = (private_charonservice_t*)charonservice;
 
+       this->builder->destroy(this->builder);
        this->creds->destroy(this->creds);
        (*env)->DeleteGlobalRef(env, this->vpn_service);
        free(this);
@@ -305,7 +319,8 @@ static void segv_handler(int signal)
 /**
  * Initialize charon and the libraries via JNI
  */
-JNI_METHOD(CharonVpnService, initializeCharon, void)
+JNI_METHOD(CharonVpnService, initializeCharon, void,
+       jobject builder)
 {
        struct sigaction action;
 
@@ -334,7 +349,7 @@ JNI_METHOD(CharonVpnService, initializeCharon, void)
                return;
        }
 
-       charonservice_init(env, this);
+       charonservice_init(env, this, builder);
 
        if (!libcharon_init("charon") ||
                !charon->initialize(charon, PLUGINS))
index e538a22..706eaa2 100644 (file)
@@ -31,6 +31,8 @@
 #ifndef CHARONSERVICE_H_
 #define CHARONSERVICE_H_
 
+#include "vpnservice_builder.h"
+
 #include <library.h>
 #include <utils/linked_list.h>
 
@@ -83,6 +85,13 @@ struct charonservice_t {
         */
        linked_list_t *(*get_trusted_certificates)(charonservice_t *this);
 
+       /**
+        * Get the current vpnservice_builder_t object
+        *
+        * @return                              VpnService.Builder instance
+        */
+       vpnservice_builder_t *(*get_vpnservice_builder)(charonservice_t *this);
+
 };
 
 /**
diff --git a/src/frontends/android/jni/libandroidbridge/vpnservice_builder.c b/src/frontends/android/jni/libandroidbridge/vpnservice_builder.c
new file mode 100644 (file)
index 0000000..6ff7325
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+#include "vpnservice_builder.h"
+#include "android_jni.h"
+
+#include <debug.h>
+#include <library.h>
+
+typedef struct private_vpnservice_builder_t private_vpnservice_builder_t;
+
+/**
+ * private data of vpnservice_builder
+ */
+struct private_vpnservice_builder_t {
+
+       /**
+        * public interface
+        */
+       vpnservice_builder_t public;
+
+       /**
+        * Java object
+        */
+       jobject builder;
+};
+
+METHOD(vpnservice_builder_t, add_address, bool,
+       private_vpnservice_builder_t *this, host_t *addr)
+{
+       JNIEnv *env;
+       jmethodID method_id;
+       jstring str;
+       char buf[INET_ADDRSTRLEN];
+
+       androidjni_attach_thread(&env);
+
+       DBG2(DBG_LIB, "builder: adding interface address %H", addr);
+
+       if (addr->get_family(addr) != AF_INET)
+       {
+               goto failed;
+       }
+       if (snprintf(buf, sizeof(buf), "%H", addr) >= sizeof(buf))
+       {
+               goto failed;
+       }
+
+       method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
+                                                                       "addAddress", "(Ljava/lang/String;I)Z");
+       if (!method_id)
+       {
+               goto failed;
+       }
+       str = (*env)->NewStringUTF(env, buf);
+       if (!str)
+       {
+               goto failed;
+       }
+       if (!(*env)->CallBooleanMethod(env, this->builder, method_id, str, 32))
+       {
+               goto failed;
+       }
+       androidjni_detach_thread();
+       return TRUE;
+
+failed:
+       DBG1(DBG_LIB, "builder: failed to add address");
+       androidjni_exception_occurred(env);
+       androidjni_detach_thread();
+       return FALSE;
+}
+
+METHOD(vpnservice_builder_t, set_mtu, bool,
+       private_vpnservice_builder_t *this, int mtu)
+{
+       JNIEnv *env;
+       jmethodID method_id;
+
+       androidjni_attach_thread(&env);
+
+       DBG2(DBG_LIB, "builder: setting MTU to %d", mtu);
+
+       method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
+                                                                       "setMtu", "(I)Z");
+       if (!method_id)
+       {
+               goto failed;
+       }
+       if (!(*env)->CallBooleanMethod(env, this->builder, method_id, mtu))
+       {
+               goto failed;
+       }
+       androidjni_detach_thread();
+       return TRUE;
+
+failed:
+       DBG1(DBG_LIB, "builder: failed to set MTU");
+       androidjni_exception_occurred(env);
+       androidjni_detach_thread();
+       return FALSE;
+}
+
+METHOD(vpnservice_builder_t, add_route, bool,
+       private_vpnservice_builder_t *this, host_t *net, int prefix)
+{
+       JNIEnv *env;
+       jmethodID method_id;
+       jstring str;
+       char buf[INET_ADDRSTRLEN];
+
+       androidjni_attach_thread(&env);
+
+       DBG2(DBG_LIB, "builder: adding route %+H/%d", net, prefix);
+
+       if (net->get_family(net) != AF_INET)
+       {
+               goto failed;
+       }
+       if (snprintf(buf, sizeof(buf), "%+H", net) >= sizeof(buf))
+       {
+               goto failed;
+       }
+
+       method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
+                                                                       "addRoute", "(Ljava/lang/String;I)Z");
+       if (!method_id)
+       {
+               goto failed;
+       }
+       str = (*env)->NewStringUTF(env, buf);
+       if (!str)
+       {
+               goto failed;
+       }
+       if (!(*env)->CallBooleanMethod(env, this->builder, method_id, str, prefix))
+       {
+               goto failed;
+       }
+       androidjni_detach_thread();
+       return TRUE;
+
+failed:
+       DBG1(DBG_LIB, "builder: failed to add route");
+       androidjni_exception_occurred(env);
+       androidjni_detach_thread();
+       return FALSE;
+}
+
+METHOD(vpnservice_builder_t, add_dns, bool,
+       private_vpnservice_builder_t *this, host_t *dns)
+{
+       JNIEnv *env;
+       jmethodID method_id;
+       jstring str;
+       char buf[INET_ADDRSTRLEN];
+
+       androidjni_attach_thread(&env);
+
+       DBG2(DBG_LIB, "builder: adding DNS server %H", dns);
+
+       if (dns->get_family(dns) != AF_INET)
+       {
+               goto failed;
+       }
+       if (snprintf(buf, sizeof(buf), "%H", dns) >= sizeof(buf))
+       {
+               goto failed;
+       }
+
+       method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
+                                                                       "addDnsServer", "(Ljava/lang/String;)Z");
+       if (!method_id)
+       {
+               goto failed;
+       }
+       str = (*env)->NewStringUTF(env, buf);
+       if (!str)
+       {
+               goto failed;
+       }
+       if (!(*env)->CallBooleanMethod(env, this->builder, method_id, str))
+       {
+               goto failed;
+       }
+       androidjni_detach_thread();
+       return TRUE;
+
+failed:
+       DBG1(DBG_LIB, "builder: failed to add DNS server");
+       androidjni_exception_occurred(env);
+       androidjni_detach_thread();
+       return FALSE;
+}
+
+METHOD(vpnservice_builder_t, establish, int,
+       private_vpnservice_builder_t *this)
+{
+       JNIEnv *env;
+       jmethodID method_id;
+       int fd;
+
+       androidjni_attach_thread(&env);
+
+       DBG2(DBG_LIB, "builder: building TUN device");
+
+       method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
+                                                                       "establish", "()I");
+       if (!method_id)
+       {
+               goto failed;
+       }
+       fd = (*env)->CallIntMethod(env, this->builder, method_id);
+       if (fd == -1)
+       {
+               goto failed;
+       }
+       androidjni_detach_thread();
+       return fd;
+
+failed:
+       DBG1(DBG_LIB, "builder: failed to build TUN device");
+       androidjni_exception_occurred(env);
+       androidjni_detach_thread();
+       return -1;
+}
+
+METHOD(vpnservice_builder_t, destroy, void,
+       private_vpnservice_builder_t *this)
+{
+       JNIEnv *env;
+
+       androidjni_attach_thread(&env);
+       (*env)->DeleteGlobalRef(env, this->builder);
+       androidjni_detach_thread();
+       free(this);
+}
+
+vpnservice_builder_t *vpnservice_builder_create(jobject builder)
+{
+       JNIEnv *env;
+       private_vpnservice_builder_t *this;
+
+       INIT(this,
+               .public = {
+                       .add_address = _add_address,
+                       .add_route = _add_route,
+                       .add_dns = _add_dns,
+                       .set_mtu = _set_mtu,
+                       .establish = _establish,
+                       .destroy = _destroy,
+               },
+       );
+
+       androidjni_attach_thread(&env);
+       this->builder = (*env)->NewGlobalRef(env, builder);
+       androidjni_detach_thread();
+
+       return &this->public;
+}
diff --git a/src/frontends/android/jni/libandroidbridge/vpnservice_builder.h b/src/frontends/android/jni/libandroidbridge/vpnservice_builder.h
new file mode 100644 (file)
index 0000000..82efd05
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup vpnservice_builder vpnservice_builder
+ * @{ @ingroup libandroidbridge
+ */
+
+#ifndef VPNSERVICE_BUILDER_H_
+#define VPNSERVICE_BUILDER_H_
+
+#include <jni.h>
+
+#include <library.h>
+#include <utils/host.h>
+
+typedef struct vpnservice_builder_t vpnservice_builder_t;
+
+/**
+ * VpnService.Builder, used to build a TUN device.
+ *
+ * Communicates with CharonVpnService.BuilderAdapter via JNI
+ */
+struct vpnservice_builder_t {
+
+       /**
+        * Add an interface address
+        *
+        * @param addr                          the desired interface address
+        * @return                                      TRUE on success
+        */
+       bool (*add_address)(vpnservice_builder_t *this, host_t *addr);
+
+       /**
+        * Add a route
+        *
+        * @param net                           the network address
+        * @param prefix_length         the prefix length
+        * @return                                      TRUE on success
+        */
+       bool (*add_route)(vpnservice_builder_t *this, host_t *net, int prefix);
+
+       /**
+        * Add a DNS server
+        *
+        * @param dns                           the address of the DNS server
+        * @return                                      TRUE on success
+        */
+       bool (*add_dns)(vpnservice_builder_t *this, host_t *dns);
+
+       /**
+        * Set the MTU for the TUN device
+        *
+        * @param mtu                           the MTU to set
+        * @return                                      TRUE on success
+        */
+       bool (*set_mtu)(vpnservice_builder_t *this,     int mtu);
+
+       /**
+        * Build the TUN device
+        *
+        * @return                                      the TUN file descriptor, -1 if failed
+        */
+       int (*establish)(vpnservice_builder_t *this);
+
+       /**
+        * Destroy a vpnservice_builder
+        */
+       void (*destroy)(vpnservice_builder_t *this);
+
+};
+
+/**
+ * Create a vpnservice_builder instance
+ *
+ * @param builder                              CharonVpnService.BuilderAdapter object
+ * @return                                             vpnservice_builder_t instance
+ */
+vpnservice_builder_t *vpnservice_builder_create(jobject builder);
+
+#endif /** VPNSERVICE_BUILDER_H_ @}*/
index 2514642..1d9881c 100644 (file)
@@ -193,7 +193,8 @@ public class CharonVpnService extends VpnService implements Runnable
                                                setError(ErrorState.NO_ERROR);
                                                setState(State.CONNECTING);
 
-                                               initializeCharon();
+                                               BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName());
+                                               initializeCharon(builder);
                                                Log.i(TAG, "charon started");
 
                                                String local_address = getLocalIPv4Address();
@@ -401,8 +402,10 @@ public class CharonVpnService extends VpnService implements Runnable
 
        /**
         * Initialization of charon, provided by libandroidbridge.so
+        *
+        * @param builder BuilderAdapter for this connection
         */
-       public native void initializeCharon();
+       public native void initializeCharon(BuilderAdapter builder);
 
        /**
         * Deinitialize charon, provided by libandroidbridge.so
@@ -450,6 +453,7 @@ public class CharonVpnService extends VpnService implements Runnable
 
        /**
         * Adapter for VpnService.Builder which is used to access it safely via JNI.
+        * There is a corresponding C object to access it from native code.
         */
        public class BuilderAdapter
        {