From 271cf5fe54d562fb15f0631efb3d5259121967b5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 29 Jan 2010 14:11:26 -0800 Subject: [PATCH] Add basic support for a location detection framework --- Makefile.am | 5 +- include/location.h | 71 ++++++++++++++ src/connman.h | 11 +++ src/element.c | 2 + src/location.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/service.c | 15 +++ 6 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 include/location.h create mode 100644 src/location.c diff --git a/Makefile.am b/Makefile.am index 15b41a6..37d5ef8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,8 @@ noinst_HEADERS = include/driver.h include/element.h include/property.h \ include/rtnl.h include/wifi.h include/task.h \ include/dbus.h include/rfkill.h include/option.h \ include/profile.h include/provider.h include/dhcp.h \ - include/utsname.h include/timeserver.h + include/utsname.h include/timeserver.h \ + include/location.h local_headers = $(foreach file,$(include_HEADERS) $(nodist_include_HEADERS) \ $(noinst_HEADERS), include/connman/$(notdir $(file))) @@ -52,7 +53,7 @@ src_connmand_SOURCES = $(gdbus_sources) $(builtin_sources) \ src/ipv4.c src/dhcp.c src/rtnl.c src/inet.c \ src/utsname.c src/timeserver.c src/rfkill.c \ src/wifi.c src/storage.c src/dbus.c src/config.c \ - src/technology.c src/counter.c + src/technology.c src/counter.c src/location.c if UDEV src_connmand_SOURCES += src/udev.c diff --git a/include/location.h b/include/location.h new file mode 100644 index 0000000..a0b01d6 --- /dev/null +++ b/include/location.h @@ -0,0 +1,71 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __CONNMAN_LOCATION_H +#define __CONNMAN_LOCATION_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * SECTION:location + * @title: Location premitives + * @short_description: Functions for detecting locations + */ + +enum connman_location_result { + CONNMAN_LOCATION_RESULT_UNKNOWN = 0, + CONNMAN_LOCATION_RESULT_PORTAL = 1, + CONNMAN_LOCATION_RESULT_ONLINE = 2, +}; + +struct connman_location; + +struct connman_location *connman_location_ref(struct connman_location *location); +void connman_location_unref(struct connman_location *location); + +enum connman_service_type connman_location_get_type(struct connman_location *location); +char *connman_location_get_interface(struct connman_location *location); +void connman_location_report_result(struct connman_location *location, + enum connman_location_result result); + +void *connman_location_get_data(struct connman_location *location); +void connman_location_set_data(struct connman_location *location, void *data); + +struct connman_location_driver { + const char *name; + enum connman_service_type type; + int priority; + int (*detect) (struct connman_location *location); + int (*finish) (struct connman_location *location); +}; + +int connman_location_driver_register(struct connman_location_driver *driver); +void connman_location_driver_unregister(struct connman_location_driver *driver); + +#ifdef __cplusplus +} +#endif + +#endif /* __CONNMAN_LOCATION_H */ diff --git a/src/connman.h b/src/connman.h index 4d869bb..593a517 100644 --- a/src/connman.h +++ b/src/connman.h @@ -409,6 +409,17 @@ void __connman_service_auto_connect(void); const char *__connman_service_type2string(enum connman_service_type type); +#include + +int __connman_location_init(void); +void __connman_location_cleanup(void); + +struct connman_location *__connman_location_create(struct connman_service *service); +struct connman_location *__connman_service_get_location(struct connman_service *service); + +int __connman_location_detect(struct connman_service *service); +int __connman_location_finish(struct connman_service *service); + #include void __connman_provider_list(DBusMessageIter *iter, void *user_data); diff --git a/src/element.c b/src/element.c index 1d2afaa..94d13b3 100644 --- a/src/element.c +++ b/src/element.c @@ -1250,6 +1250,7 @@ int __connman_element_init(const char *device, const char *nodevice) __connman_technology_init(); __connman_notifier_init(); + __connman_location_init(); __connman_service_init(); __connman_provider_init(); __connman_network_init(); @@ -1344,6 +1345,7 @@ void __connman_element_cleanup(void) __connman_device_cleanup(); __connman_network_cleanup(); __connman_service_cleanup(); + __connman_location_cleanup(); __connman_notifier_cleanup(); __connman_technology_cleanup(); diff --git a/src/location.c b/src/location.c new file mode 100644 index 0000000..a0a8c41 --- /dev/null +++ b/src/location.c @@ -0,0 +1,275 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "connman.h" + +struct connman_location { + gint refcount; + struct connman_service *service; + enum connman_location_result result; + + struct connman_location_driver *driver; + void *driver_data; +}; + +/** + * connman_location_ref: + * @location: Location structure + * + * Increase reference counter of location + */ +struct connman_location *connman_location_ref(struct connman_location *location) +{ + g_atomic_int_inc(&location->refcount); + + return location; +} + +/** + * connman_location_unref: + * @location: Location structure + * + * Decrease reference counter of location + */ +void connman_location_unref(struct connman_location *location) +{ + if (g_atomic_int_dec_and_test(&location->refcount) == FALSE) + return; + + if (location->driver) { + location->driver->finish(location); + location->driver = NULL; + } + + g_free(location); +} + +/** + * connman_location_get_type: + * @location: Location structure + * + * Get the service type of location + */ +enum connman_service_type connman_location_get_type(struct connman_location *location) +{ + if (location == NULL) + return CONNMAN_SERVICE_TYPE_UNKNOWN; + + return connman_service_get_type(location->service); +} + +/** + * connman_location_get_interface: + * @location: location structure + * + * Get network interface of location + */ +char *connman_location_get_interface(struct connman_location *location) +{ + if (location == NULL) + return NULL; + + return connman_service_get_interface(location->service); +} + +/** + * connman_location_get_data: + * @location: Location structure + * + * Get private location data pointer + */ +void *connman_location_get_data(struct connman_location *location) +{ + return location->driver_data; +} + +/** + * connman_location_set_data: + * @location: Location structure + * @data: data pointer + * + * Set private location data pointer + */ +void connman_location_set_data(struct connman_location *location, void *data) +{ + location->driver_data = data; +} + +static GSList *driver_list = NULL; + +static gint compare_priority(gconstpointer a, gconstpointer b) +{ + const struct connman_location_driver *driver1 = a; + const struct connman_location_driver *driver2 = b; + + return driver2->priority - driver1->priority; +} + +/** + * connman_location_driver_register: + * @driver: Location driver definition + * + * Register a new Location driver + * + * Returns: %0 on success + */ +int connman_location_driver_register(struct connman_location_driver *driver) +{ + DBG("driver %p name %s", driver, driver->name); + + driver_list = g_slist_insert_sorted(driver_list, driver, + compare_priority); + + return 0; +} + +/** + * connman_location_driver_unregister: + * @driver: Location driver definition + * + * Remove a previously registered Location driver + */ +void connman_location_driver_unregister(struct connman_location_driver *driver) +{ + DBG("driver %p name %s", driver, driver->name); + + driver_list = g_slist_remove(driver_list, driver); +} + +/** + * connman_location_report_result: + * @location: location structure + * @result: result information + * + * Report result of a location detection + */ +void connman_location_report_result(struct connman_location *location, + enum connman_location_result result) +{ + DBG("location %p result %d", location, result); + + if (location == NULL) + return; + + if (location->result == result) + return; + + location->result = result; + + switch (location->result) { + case CONNMAN_LOCATION_RESULT_UNKNOWN: + return; + case CONNMAN_LOCATION_RESULT_PORTAL: + //__connman_service_indicate_state(location->service, + // CONNMAN_SERVICE_STATE_LOGIN); + break; + case CONNMAN_LOCATION_RESULT_ONLINE: + //__connman_service_indicate_state(location->service, + // CONNMAN_SERVICE_STATE_ONLINE); + break; + } +} + +struct connman_location *__connman_location_create(struct connman_service *service) +{ + struct connman_location *location; + + DBG("service %p", service); + + if (service == NULL) + return NULL; + + location = g_try_new0(struct connman_location, 1); + if (location == NULL) + return NULL; + + DBG("location %p", location); + + location->refcount = 1; + + location->service = service; + location->result = CONNMAN_LOCATION_RESULT_UNKNOWN; + + return location; +} + +int __connman_location_detect(struct connman_service *service) +{ + struct connman_location *location; + GSList *list; + + DBG("service %p", service); + + location = __connman_service_get_location(service); + if (location == NULL) + return -EINVAL; + + if (location->driver) + return -EBUSY; + + for (list = driver_list; list; list = list->next) { + struct connman_location_driver *driver = list->data; + + DBG("driver %p name %s", driver, driver->name); + + if (driver->detect(location) == 0) { + location->driver = driver; + break; + } + } + + if (location->driver == NULL) + connman_location_report_result(location, + CONNMAN_LOCATION_RESULT_ONLINE); + + return 0; +} + +int __connman_location_finish(struct connman_service *service) +{ + struct connman_location *location; + + DBG("service %p", service); + + location = __connman_service_get_location(service); + if (location == NULL) + return -EINVAL; + + if (location->driver) { + location->driver->finish(location); + location->driver = NULL; + } + + return 0; +} + +int __connman_location_init(void) +{ + return 0; +} + +void __connman_location_cleanup(void) +{ +} diff --git a/src/service.c b/src/service.c index 1eccbac..116a596 100644 --- a/src/service.c +++ b/src/service.c @@ -75,6 +75,7 @@ struct connman_service { char *phase2; DBusMessage *pending; guint timeout; + struct connman_location *location; }; static void append_path(gpointer value, gpointer user_data) @@ -1251,6 +1252,9 @@ static void service_free(gpointer user_data) service->ipconfig = NULL; } + if (service->location != NULL) + connman_location_unref(service->location); + g_free(service->mcc); g_free(service->mnc); g_free(service->apn); @@ -1336,9 +1340,16 @@ struct connman_service *connman_service_create(void) __connman_service_initialize(service); + service->location = __connman_location_create(service); + return service; } +struct connman_location *__connman_service_get_location(struct connman_service *service) +{ + return service->location; +} + /** * connman_service_ref: * @service: service structure @@ -1588,7 +1599,11 @@ int __connman_service_indicate_state(struct connman_service *service, __connman_notifier_connect(service->type); default_changed(); + + __connman_location_detect(service); } else if (state == CONNMAN_SERVICE_STATE_DISCONNECT) { + __connman_location_finish(service); + default_changed(); __connman_notifier_disconnect(service->type); -- 2.7.4