diff options
Diffstat (limited to 'src/frontends/android/jni/libandroidbridge')
9 files changed, 493 insertions, 51 deletions
diff --git a/src/frontends/android/jni/libandroidbridge/Android.mk b/src/frontends/android/jni/libandroidbridge/Android.mk index f47e39656..b1fa4d1cb 100644 --- a/src/frontends/android/jni/libandroidbridge/Android.mk +++ b/src/frontends/android/jni/libandroidbridge/Android.mk @@ -11,6 +11,7 @@ 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/network_manager.c kernel/network_manager.h \ vpnservice_builder.c vpnservice_builder.h # build libandroidbridge ------------------------------------------------------- diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c index 2a115d2f9..b00567f60 100644 --- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c @@ -59,11 +59,6 @@ struct private_android_service_t { char *type; /** - * local ipv4 address - */ - char *local_address; - - /** * gateway */ char *gateway; @@ -362,7 +357,6 @@ METHOD(listener_t, child_updown, bool, { /* disable the hooks registered to catch initiation failures */ this->public.listener.ike_updown = NULL; - this->public.listener.ike_state_change = NULL; if (!setup_tun_device(this, ike_sa, child_sa)) { DBG1(DBG_DMN, "failed to setup TUN device"); @@ -403,19 +397,6 @@ METHOD(listener_t, ike_updown, bool, return TRUE; } -METHOD(listener_t, ike_state_change, bool, - private_android_service_t *this, ike_sa_t *ike_sa, ike_sa_state_t state) -{ - /* this call back is only registered during initiation */ - if (this->ike_sa == ike_sa && state == IKE_DESTROYING) - { - charonservice->update_status(charonservice, - CHARONSERVICE_UNREACHABLE_ERROR); - return FALSE; - } - return TRUE; -} - METHOD(listener_t, alert, bool, private_android_service_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args) @@ -432,6 +413,15 @@ METHOD(listener_t, alert, bool, charonservice->update_status(charonservice, CHARONSERVICE_PEER_AUTH_ERROR); break; + case ALERT_PEER_INIT_UNREACHABLE: + this->lock->read_lock(this->lock); + if (this->tunfd < 0) + { /* only handle this if we are not reestablishing the SA */ + charonservice->update_status(charonservice, + CHARONSERVICE_UNREACHABLE_ERROR); + } + this->lock->unlock(this->lock); + break; default: break; } @@ -455,9 +445,8 @@ METHOD(listener_t, ike_reestablish, bool, if (this->ike_sa == old) { this->ike_sa = new; - /* re-register hooks to detect initiation failures */ + /* re-register hook to detect initiation failures */ this->public.listener.ike_updown = _ike_updown; - this->public.listener.ike_state_change = _ike_state_change; /* the TUN device will be closed when the new CHILD_SA is established */ } return TRUE; @@ -480,13 +469,13 @@ static job_requeue_t initiate(private_android_service_t *this) } }; - ike_cfg = ike_cfg_create(TRUE, TRUE, this->local_address, FALSE, + ike_cfg = ike_cfg_create(TRUE, TRUE, "0.0.0.0", FALSE, charon->socket->get_port(charon->socket, FALSE), this->gateway, FALSE, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create("android", IKEV2, ike_cfg, CERT_SEND_IF_ASKED, - UNIQUE_REPLACE, 1, /* keyingtries */ + UNIQUE_REPLACE, 0, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ TRUE, FALSE, /* mobike, aggressive */ @@ -538,10 +527,14 @@ static job_requeue_t initiate(private_android_service_t *this) peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); child_cfg = child_cfg_create("android", &lifetime, NULL, TRUE, MODE_TUNNEL, - ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, - 0, 0, NULL, NULL, 0); - child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); - ts = traffic_selector_create_dynamic(0, 0, 65535); + ACTION_NONE, ACTION_RESTART, ACTION_RESTART, + FALSE, 0, 0, NULL, NULL, 0); + /* create an ESP proposal with the algorithms currently supported by + * libipsec, no PFS for now */ + child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP, + "aes128-aes192-aes256-sha1-sha256-sha384-sha512")); + ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0", + 0, "255.255.255.255", 65535); child_cfg->add_traffic_selector(child_cfg, TRUE, ts); ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0", 0, "255.255.255.255", 65535); @@ -588,7 +581,6 @@ METHOD(android_service_t, destroy, void, close_tun_device(this); this->lock->destroy(this->lock); free(this->type); - free(this->local_address); free(this->gateway); free(this->username); if (this->password) @@ -603,8 +595,8 @@ METHOD(android_service_t, destroy, void, * See header */ android_service_t *android_service_create(android_creds_t *creds, char *type, - char *local_address, char *gateway, - char *username, char *password) + char *gateway, char *username, + char *password) { private_android_service_t *this; @@ -614,14 +606,12 @@ android_service_t *android_service_create(android_creds_t *creds, char *type, .ike_rekey = _ike_rekey, .ike_reestablish = _ike_reestablish, .ike_updown = _ike_updown, - .ike_state_change = _ike_state_change, .child_updown = _child_updown, .alert = _alert, }, .destroy = _destroy, }, .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), - .local_address = local_address, .username = username, .password = password, .gateway = gateway, diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.h b/src/frontends/android/jni/libandroidbridge/backend/android_service.h index 52c3dc5c8..1bfdcf994 100644 --- a/src/frontends/android/jni/libandroidbridge/backend/android_service.h +++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.h @@ -53,13 +53,12 @@ struct android_service_t { * * @param creds Android specific credential set * @param type VPN type (see VpnType.java) - * @param local_address local ip address * @param gateway gateway address * @param username user name (local identity) * @param password password (if any) */ android_service_t *android_service_create(android_creds_t *creds, char *type, - char *local_address, char *gateway, - char *username, char *password); + char *gateway, char *username, + char *password); #endif /** ANDROID_SERVICE_H_ @}*/ diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.c b/src/frontends/android/jni/libandroidbridge/charonservice.c index ef4d42edf..1fde9887b 100644 --- a/src/frontends/android/jni/libandroidbridge/charonservice.c +++ b/src/frontends/android/jni/libandroidbridge/charonservice.c @@ -38,7 +38,7 @@ #define ANDROID_DEBUG_LEVEL 1 #define ANDROID_RETRASNMIT_TRIES 3 -#define ANDROID_RETRANSMIT_TIMEOUT 3.0 +#define ANDROID_RETRANSMIT_TIMEOUT 2.0 #define ANDROID_RETRANSMIT_BASE 1.4 typedef struct private_charonservice_t private_charonservice_t; @@ -74,9 +74,19 @@ struct private_charonservice_t { vpnservice_builder_t *builder; /** + * NetworkManager instance (accessed via JNI) + */ + network_manager_t *network_manager; + + /** * CharonVpnService reference */ jobject vpn_service; + + /** + * Sockets that were bypassed and we keep track for + */ + linked_list_t *sockets; }; /** @@ -172,8 +182,10 @@ failed: return success; } -METHOD(charonservice_t, bypass_socket, bool, - private_charonservice_t *this, int fd, int family) +/** + * Bypass a single socket + */ +static bool bypass_single_socket(intptr_t fd, private_charonservice_t *this) { JNIEnv *env; jmethodID method_id; @@ -188,7 +200,7 @@ METHOD(charonservice_t, bypass_socket, bool, } if (!(*env)->CallBooleanMethod(env, this->vpn_service, method_id, fd)) { - DBG1(DBG_CFG, "VpnService.protect() failed"); + DBG2(DBG_KNL, "VpnService.protect() failed"); goto failed; } androidjni_detach_thread(); @@ -200,6 +212,19 @@ failed: return FALSE; } +METHOD(charonservice_t, bypass_socket, bool, + private_charonservice_t *this, int fd, int family) +{ + if (fd >= 0) + { + this->sockets->insert_last(this->sockets, (void*)(intptr_t)fd); + return bypass_single_socket((intptr_t)fd, this); + } + this->sockets->invoke_function(this->sockets, (void*)bypass_single_socket, + this); + return TRUE; +} + /** * Converts the given Java array of byte arrays (byte[][]) to a linked list * of chunk_t objects. @@ -330,22 +355,26 @@ METHOD(charonservice_t, get_vpnservice_builder, vpnservice_builder_t*, return this->builder; } +METHOD(charonservice_t, get_network_manager, network_manager_t*, + private_charonservice_t *this) +{ + return this->network_manager; +} + /** * Initiate a new connection * - * @param local local ip address (gets owned) * @param gateway gateway address (gets owned) * @param username username (gets owned) * @param password password (gets owned) */ -static void initiate(char *type, char *local, char *gateway, - char *username, char *password) +static void initiate(char *type, char *gateway, char *username, char *password) { private_charonservice_t *this = (private_charonservice_t*)charonservice; this->creds->clear(this->creds); DESTROY_IF(this->service); - this->service = android_service_create(this->creds, type, local, gateway, + this->service = android_service_create(this->creds, type, gateway, username, password); } @@ -400,10 +429,13 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder) .get_user_certificate = _get_user_certificate, .get_user_key = _get_user_key, .get_vpnservice_builder = _get_vpnservice_builder, + .get_network_manager = _get_network_manager, }, .attr = android_attr_create(), .creds = android_creds_create(), .builder = vpnservice_builder_create(builder), + .network_manager = network_manager_create(service), + .sockets = linked_list_create(), .vpn_service = (*env)->NewGlobalRef(env, service), ); charonservice = &this->public; @@ -439,6 +471,8 @@ static void charonservice_deinit(JNIEnv *env) { private_charonservice_t *this = (private_charonservice_t*)charonservice; + this->network_manager->destroy(this->network_manager); + this->sockets->destroy(this->sockets); this->builder->destroy(this->builder); this->creds->destroy(this->creds); this->attr->destroy(this->attr); @@ -555,16 +589,14 @@ JNI_METHOD(CharonVpnService, deinitializeCharon, void) * Initiate SA */ JNI_METHOD(CharonVpnService, initiate, void, - jstring jtype, jstring jlocal_address, jstring jgateway, jstring jusername, - jstring jpassword) + jstring jtype, jstring jgateway, jstring jusername, jstring jpassword) { - char *type, *local_address, *gateway, *username, *password; + char *type, *gateway, *username, *password; type = androidjni_convert_jstring(env, jtype); - local_address = androidjni_convert_jstring(env, jlocal_address); gateway = androidjni_convert_jstring(env, jgateway); username = androidjni_convert_jstring(env, jusername); password = androidjni_convert_jstring(env, jpassword); - initiate(type, local_address, gateway, username, password); + initiate(type, gateway, username, password); } diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.h b/src/frontends/android/jni/libandroidbridge/charonservice.h index 376f55014..4b5839f5e 100644 --- a/src/frontends/android/jni/libandroidbridge/charonservice.h +++ b/src/frontends/android/jni/libandroidbridge/charonservice.h @@ -32,6 +32,7 @@ #define CHARONSERVICE_H_ #include "vpnservice_builder.h" +#include "kernel/network_manager.h" #include <library.h> #include <utils/linked_list.h> @@ -69,7 +70,9 @@ struct charonservice_t { /** * Install a bypass policy for the given socket using the protect() Method - * of the Android VpnService interface + * of the Android VpnService interface. + * + * Use -1 as fd to re-bypass previously bypassed sockets. * * @param fd socket file descriptor * @param family socket protocol family @@ -111,6 +114,12 @@ struct charonservice_t { */ vpnservice_builder_t *(*get_vpnservice_builder)(charonservice_t *this); + /** + * Get the current network_manager_t object + * + * @return NetworkManager instance + */ + network_manager_t *(*get_network_manager)(charonservice_t *this); }; /** diff --git a/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c b/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c index 08cc61610..85fe5d4c1 100644 --- a/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c +++ b/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c @@ -79,7 +79,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t, u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, bool encap, bool new_encap, mark_t mark) { - return NOT_SUPPORTED; + return ipsec->sas->update_sa(ipsec->sas, spi, protocol, cpi, src, dst, + new_src, new_dst, encap, new_encap, mark); } METHOD(kernel_ipsec_t, query_sa, status_t, diff --git a/src/frontends/android/jni/libandroidbridge/kernel/android_net.c b/src/frontends/android/jni/libandroidbridge/kernel/android_net.c index e29f95510..430c95bc8 100644 --- a/src/frontends/android/jni/libandroidbridge/kernel/android_net.c +++ b/src/frontends/android/jni/libandroidbridge/kernel/android_net.c @@ -14,6 +14,15 @@ #include "android_net.h" +#include "../charonservice.h" +#include <hydra.h> +#include <debug.h> +#include <processing/jobs/callback_job.h> +#include <threading/mutex.h> + +/** delay before firing roam events (ms) */ +#define ROAM_DELAY 100 + typedef struct private_kernel_android_net_t private_kernel_android_net_t; struct private_kernel_android_net_t { @@ -22,8 +31,66 @@ struct private_kernel_android_net_t { * Public kernel interface */ kernel_android_net_t public; + + /** + * Reference to NetworkManager object + */ + network_manager_t *network_manager; + + /** + * earliest time of the next roam event + */ + timeval_t next_roam; + + /** + * mutex to check and update roam event time + */ + mutex_t *mutex; }; +/** + * callback function that raises the delayed roam event + */ +static job_requeue_t roam_event() +{ + /* this will fail if no connection is up */ + charonservice->bypass_socket(charonservice, -1, 0); + hydra->kernel_interface->roam(hydra->kernel_interface, TRUE); + return JOB_REQUEUE_NONE; +} + +/** + * Listen for connectivity change events and queue a roam event + */ +static void connectivity_cb(private_kernel_android_net_t *this, + bool disconnected) +{ + timeval_t now; + job_t *job; + + time_monotonic(&now); + this->mutex->lock(this->mutex); + if (!timercmp(&now, &this->next_roam, >)) + { + this->mutex->unlock(this->mutex); + return; + } + timeval_add_ms(&now, ROAM_DELAY); + this->next_roam = now; + this->mutex->unlock(this->mutex); + + job = (job_t*)callback_job_create((callback_job_cb_t)roam_event, NULL, + NULL, NULL); + lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY); +} + +METHOD(kernel_net_t, get_source_addr, host_t*, + private_kernel_android_net_t *this, host_t *dest, host_t *src) +{ + return this->network_manager->get_local_address(this->network_manager, + dest->get_family(dest) == AF_INET); +} + METHOD(kernel_net_t, add_ip, status_t, private_kernel_android_net_t *this, host_t *virtual_ip, host_t *iface_ip) { @@ -34,6 +101,9 @@ METHOD(kernel_net_t, add_ip, status_t, METHOD(kernel_net_t, destroy, void, private_kernel_android_net_t *this) { + this->network_manager->remove_connectivity_cb(this->network_manager, + (void*)connectivity_cb); + this->mutex->destroy(this->mutex); free(this); } @@ -47,7 +117,7 @@ kernel_android_net_t *kernel_android_net_create() INIT(this, .public = { .interface = { - .get_source_addr = (void*)return_null, + .get_source_addr = _get_source_addr, .get_nexthop = (void*)return_null, .get_interface = (void*)return_null, .create_address_enumerator = (void*)enumerator_create_empty, @@ -58,7 +128,12 @@ kernel_android_net_t *kernel_android_net_create() .destroy = _destroy, }, }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .network_manager = charonservice->get_network_manager(charonservice), ); + timerclear(&this->next_roam); + this->network_manager->add_connectivity_cb(this->network_manager, + (void*)connectivity_cb, this); return &this->public; }; diff --git a/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c new file mode 100644 index 000000000..9c97fbb14 --- /dev/null +++ b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2012 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. + */ + +#include "network_manager.h" + +#include "../android_jni.h" +#include "../charonservice.h" +#include <debug.h> +#include <threading/mutex.h> + +typedef struct private_network_manager_t private_network_manager_t; + +struct private_network_manager_t { + + /** + * Public interface + */ + network_manager_t public; + + /** + * Reference to NetworkManager object + */ + jobject obj; + + /** + * Java class for NetworkManager + */ + jclass cls; + + /** + * Registered callback + */ + struct { + connectivity_cb_t cb; + void *data; + } connectivity_cb; + + /** + * Mutex to access callback + */ + mutex_t *mutex; +}; + +METHOD(network_manager_t, get_local_address, host_t*, + private_network_manager_t *this, bool ipv4) +{ + JNIEnv *env; + jmethodID method_id; + jstring jaddr; + char *addr; + host_t *host; + + androidjni_attach_thread(&env); + method_id = (*env)->GetMethodID(env, this->cls, "getLocalAddress", + "(Z)Ljava/lang/String;"); + if (!method_id) + { + goto failed; + } + jaddr = (*env)->CallObjectMethod(env, this->obj, method_id, ipv4); + if (!jaddr) + { + goto failed; + } + addr = androidjni_convert_jstring(env, jaddr); + androidjni_detach_thread(); + host = host_create_from_string(addr, 0); + free(addr); + return host; + +failed: + androidjni_exception_occurred(env); + androidjni_detach_thread(); + return NULL; +} + +JNI_METHOD(NetworkManager, networkChanged, void, + bool disconnected) +{ + private_network_manager_t *nm; + + nm = (private_network_manager_t*)charonservice->get_network_manager( + charonservice); + nm->mutex->lock(nm->mutex); + if (nm->connectivity_cb.cb) + { + nm->connectivity_cb.cb(nm->connectivity_cb.data, disconnected); + } + nm->mutex->unlock(nm->mutex); +} + +METHOD(network_manager_t, add_connectivity_cb, void, + private_network_manager_t *this, connectivity_cb_t cb, void *data) +{ + this->mutex->lock(this->mutex); + if (!this->connectivity_cb.cb) + { + JNIEnv *env; + jmethodID method_id; + + androidjni_attach_thread(&env); + method_id = (*env)->GetMethodID(env, this->cls, "Register", "()V"); + if (!method_id) + { + androidjni_exception_occurred(env); + } + else + { + (*env)->CallVoidMethod(env, this->obj, method_id); + if (!androidjni_exception_occurred(env)) + { + this->connectivity_cb.cb = cb; + this->connectivity_cb.data = data; + } + androidjni_detach_thread(); + } + } + this->mutex->unlock(this->mutex); +} + +/** + * Unregister the NetworkManager via JNI. + * + * this->mutex has to be locked + */ +static void unregister_network_manager(private_network_manager_t *this) +{ + JNIEnv *env; + jmethodID method_id; + + androidjni_attach_thread(&env); + method_id = (*env)->GetMethodID(env, this->cls, "Unregister", "()V"); + if (!method_id) + { + androidjni_exception_occurred(env); + } + else + { + (*env)->CallVoidMethod(env, this->obj, method_id); + androidjni_exception_occurred(env); + } + androidjni_detach_thread(); +} + +METHOD(network_manager_t, remove_connectivity_cb, void, + private_network_manager_t *this, connectivity_cb_t cb) +{ + this->mutex->lock(this->mutex); + if (this->connectivity_cb.cb == cb) + { + this->connectivity_cb.cb = NULL; + unregister_network_manager(this); + } + this->mutex->unlock(this->mutex); +} + +METHOD(network_manager_t, destroy, void, + private_network_manager_t *this) +{ + JNIEnv *env; + + this->mutex->lock(this->mutex); + if (this->connectivity_cb.cb) + { + this->connectivity_cb.cb = NULL; + unregister_network_manager(this); + } + this->mutex->unlock(this->mutex); + + androidjni_attach_thread(&env); + if (this->obj) + { + (*env)->DeleteGlobalRef(env, this->obj); + } + if (this->cls) + { + (*env)->DeleteGlobalRef(env, this->cls); + } + androidjni_detach_thread(); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * Described in header. + */ +network_manager_t *network_manager_create(jobject context) +{ + private_network_manager_t *this; + JNIEnv *env; + jmethodID method_id; + jobject obj; + jclass cls; + + INIT(this, + .public = { + .get_local_address = _get_local_address, + .add_connectivity_cb = _add_connectivity_cb, + .remove_connectivity_cb = _remove_connectivity_cb, + .destroy = _destroy, + }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + + androidjni_attach_thread(&env); + cls = (*env)->FindClass(env, JNI_PACKAGE_STRING "/NetworkManager"); + if (!cls) + { + goto failed; + } + this->cls = (*env)->NewGlobalRef(env, cls); + method_id = (*env)->GetMethodID(env, cls, "<init>", + "(Landroid/content/Context;)V"); + if (!method_id) + { + goto failed; + } + obj = (*env)->NewObject(env, cls, method_id, context); + if (!obj) + { + goto failed; + } + this->obj = (*env)->NewGlobalRef(env, obj); + androidjni_detach_thread(); + return &this->public; + +failed: + DBG1(DBG_KNL, "failed to build NetworkManager object"); + androidjni_exception_occurred(env); + androidjni_detach_thread(); + destroy(this); + return NULL; +}; diff --git a/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h new file mode 100644 index 000000000..634816405 --- /dev/null +++ b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012 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. + */ + +/** + * @defgroup network_manager network_manager + * @{ @ingroup kernel_android + */ + +#ifndef NETWORK_MANAGER_H_ +#define NETWORK_MANAGER_H_ + +#include <jni.h> + +#include <library.h> +#include <utils/host.h> + +typedef struct network_manager_t network_manager_t; + +/** + * Callback called if connectivity changes somehow. + * + * Implementation should be quick as the call is made by the Java apps main + * thread. + * + * @param data data supplied during registration + * @param disconnected TRUE if currently disconnected + */ +typedef void (*connectivity_cb_t)(void *data, bool disconnected); + +/** + * NetworkManager, used to listen for network changes and retrieve local IP + * addresses. + * + * Communicates with NetworkManager via JNI + */ +struct network_manager_t { + + /** + * Get a local address + * + * @param ipv4 TRUE to get an IPv4 address + * @return the address or NULL if none available + */ + host_t *(*get_local_address)(network_manager_t *this, bool ipv4); + + /** + * Register a callback that is called if connectivity changes + * + * @note Only the first registered callback is currently used + * + * @param cb callback to register + * @param data data provided to callback + */ + void (*add_connectivity_cb)(network_manager_t *this, connectivity_cb_t cb, + void *data); + + /** + * Unregister a previously registered callback for connectivity changes + * + * @param cb previously registered callback + */ + void (*remove_connectivity_cb)(network_manager_t *this, + connectivity_cb_t cb); + + /** + * Destroy a network_manager_t instance + */ + void (*destroy)(network_manager_t *this); +}; + +/** + * Create a network_manager_t instance + * + * @param context Context object + * @return network_manager_t instance + */ +network_manager_t *network_manager_create(jobject context); + +#endif /** NETWORK_MANAGER_H_ @}*/ |