From ffb18df525c7435ec77ecb5ceac14cb357ca57d7 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 28 Jun 2008 10:27:57 +0200 Subject: [PATCH] Add new element infrastructure --- include/Makefile.am | 2 +- include/driver.h | 54 +++++++ include/element.h | 123 ++++++++++++++++ src/Makefile.am | 3 +- src/connman.h | 8 + src/element.c | 417 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 4 + 7 files changed, 609 insertions(+), 2 deletions(-) create mode 100644 include/driver.h create mode 100644 include/element.h create mode 100644 src/element.c diff --git a/include/Makefile.am b/include/Makefile.am index 15af374..e2dacdc 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,7 +1,7 @@ includedir = @includedir@/connman -include_HEADERS = log.h plugin.h dbus.h +include_HEADERS = log.h plugin.h driver.h element.h dbus.h noinst_HEADERS = iface.h rtnl.h dhcp.h resolver.h diff --git a/include/driver.h b/include/driver.h new file mode 100644 index 0000000..3d0ad92 --- /dev/null +++ b/include/driver.h @@ -0,0 +1,54 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2007-2008 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_DRIVER_H +#define __CONNMAN_DRIVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define CONNMAN_DRIVER_PRIORITY_LOW -100 +#define CONNMAN_DRIVER_PRIORITY_DEFAULT 0 +#define CONNMAN_DRIVER_PRIORITY_HIGH 100 + +struct connman_driver { + const char *name; + enum connman_element_type type; + enum connman_element_type subtype; + int priority; + int (*probe) (struct connman_element *element); + void (*remove) (struct connman_element *element); + int (*update) (struct connman_element *element); + int (*connect) (struct connman_element *element); + int (*disconnect) (struct connman_element *element); +}; + +extern int connman_driver_register(struct connman_driver *driver); +extern void connman_driver_unregister(struct connman_driver *driver); + +#ifdef __cplusplus +} +#endif + +#endif /* __CONNMAN_DRIVER_H */ diff --git a/include/element.h b/include/element.h new file mode 100644 index 0000000..dfcbd0f --- /dev/null +++ b/include/element.h @@ -0,0 +1,123 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2007-2008 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_ELEMENT_H +#define __CONNMAN_ELEMENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +enum connman_element_state { + CONNMAN_ELEMENT_STATE_UNKNOWN = 0, + CONNMAN_ELEMENT_STATE_CONNECT = 1, + CONNMAN_ELEMENT_STATE_CONNECTED = 2, + CONNMAN_ELEMENT_STATE_CLOSED = 3, +}; + +enum connman_element_type { + CONNMAN_ELEMENT_TYPE_UNKNOWN = 0, + CONNMAN_ELEMENT_TYPE_ROOT = 1, + CONNMAN_ELEMENT_TYPE_DEVICE = 2, + CONNMAN_ELEMENT_TYPE_NETWORK = 3, + CONNMAN_ELEMENT_TYPE_IPV4 = 4, + CONNMAN_ELEMENT_TYPE_IPV6 = 5, + CONNMAN_ELEMENT_TYPE_DHCP = 6, + CONNMAN_ELEMENT_TYPE_BOOTP = 7, + CONNMAN_ELEMENT_TYPE_ZEROCONF = 8, + + CONNMAN_ELEMENT_TYPE_CONNECTION = 42, +}; + +enum connman_element_subtype { + CONNMAN_ELEMENT_SUBTYPE_UNKNOWN = 0, + CONNMAN_ELEMENT_SUBTYPE_ETHERNET = 1, + CONNMAN_ELEMENT_SUBTYPE_WIFI = 2, + CONNMAN_ELEMENT_SUBTYPE_WIMAX = 3, + CONNMAN_ELEMENT_SUBTYPE_MODEM = 4, + CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH = 5, +}; + +struct connman_driver; + +struct connman_element { + gint refcount; + gchar *name; + gchar *path; + enum connman_element_type type; + enum connman_element_subtype subtype; + enum connman_element_state state; + + struct connman_element *parent; + + struct connman_driver *driver; + void *driver_data; + + struct { + gchar *driver; + gchar *vendor; + gchar *product; + } info; + + struct { + int index; + short flags; + gchar *name; + } netdev; + + struct { + gchar *address; + gchar *netmask; + gchar *gateway; + gchar *network; + gchar *broadcast; + gchar *nameserver; + } ipv4; +}; + +extern struct connman_element *connman_element_create(void); +extern struct connman_element *connman_element_ref(struct connman_element *element); +extern void connman_element_unref(struct connman_element *element); + +extern int connman_element_register(struct connman_element *element, + struct connman_element *parent); +extern void connman_element_unregister(struct connman_element *element); +extern void connman_element_update(struct connman_element *element); + +static inline void *connman_element_get_data(struct connman_element *element) +{ + return element->driver_data; +} + +static inline void connman_element_set_data(struct connman_element *element, + void *data) +{ + element->driver_data = data; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __CONNMAN_ELEMENT_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 1f585c7..1ab7d7a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,8 @@ DISTCLEANFILES = $(service_DATA) sbin_PROGRAMS = connmand -connmand_SOURCES = main.c connman.h log.c manager.c agent.c plugin.c \ +connmand_SOURCES = main.c connman.h log.c plugin.c element.c \ + manager.c agent.c \ iface.c iface-storage.c iface-helper.c iface-inet.c \ network.c rtnl.c dhcp.c resolver.c diff --git a/src/connman.h b/src/connman.h index e04ddf5..e4f51df 100644 --- a/src/connman.h +++ b/src/connman.h @@ -47,6 +47,14 @@ void __connman_log_cleanup(void); int __connman_plugin_init(void); void __connman_plugin_cleanup(void); +#include +#include + +int __connman_element_init(void); +void __connman_element_cleanup(void); + +void __connman_element_list(DBusMessageIter *iter); + #include int __connman_iface_init(DBusConnection *conn, const char *interface); diff --git a/src/element.c b/src/element.c new file mode 100644 index 0000000..71332d0 --- /dev/null +++ b/src/element.c @@ -0,0 +1,417 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2007-2008 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 + +#include +#include + +#include "connman.h" + +static GStaticMutex driver_mutex = G_STATIC_MUTEX_INIT; +static GSList *driver_list = NULL; +static GThreadPool *driver_thread; + +static GStaticMutex element_mutex = G_STATIC_MUTEX_INIT; +static GNode *element_root = NULL; +static GThreadPool *element_thread; + +static gboolean append_path(GNode *node, gpointer data) +{ + struct connman_element *element = node->data; + DBusMessageIter *iter = data; + + DBG("element %p name %s", element, element->name); + + if (element->type == CONNMAN_ELEMENT_TYPE_ROOT) + return FALSE; + + dbus_message_iter_append_basic(iter, + DBUS_TYPE_OBJECT_PATH, &element->path); + + return FALSE; +} + +void __connman_element_list(DBusMessageIter *iter) +{ + DBG(""); + + g_static_mutex_lock(&element_mutex); + g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + append_path, iter); + g_static_mutex_unlock(&element_mutex); +} + +static gint compare_priority(gconstpointer a, gconstpointer b) +{ + const struct connman_driver *driver1 = a; + const struct connman_driver *driver2 = b; + + return driver2->priority - driver1->priority; +} + +int connman_driver_register(struct connman_driver *driver) +{ + DBG("driver %p name %s", driver, driver->name); + + if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT) + return -1; + + if (!driver->probe) + return -EINVAL; + + g_static_mutex_lock(&driver_mutex); + driver_list = g_slist_insert_sorted(driver_list, driver, + compare_priority); + g_static_mutex_unlock(&driver_mutex); + + g_thread_pool_push(driver_thread, driver, NULL); + + return 0; +} + +static gboolean remove_driver(GNode *node, gpointer data) +{ + struct connman_element *element = node->data; + struct connman_driver *driver = data; + + DBG("element %p name %s", element, element->name); + + if (element->driver == driver) { + if (driver->remove) + driver->remove(element); + element->driver = NULL; + } + + return FALSE; +} + +void connman_driver_unregister(struct connman_driver *driver) +{ + DBG("driver %p name %s", driver, driver->name); + + g_static_mutex_lock(&element_mutex); + g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1, + remove_driver, driver); + g_static_mutex_unlock(&element_mutex); + + g_static_mutex_lock(&driver_mutex); + driver_list = g_slist_remove(driver_list, driver); + g_static_mutex_unlock(&driver_mutex); +} + +struct connman_element *connman_element_create(void) +{ + struct connman_element *element; + + element = g_new0(struct connman_element, 1); + + DBG("element %p", element); + + element->refcount = 1; + + element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN; + element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN; + element->state = CONNMAN_ELEMENT_STATE_CLOSED; + + element->netdev.index = -1; + + return element; +} + +struct connman_element *connman_element_ref(struct connman_element *element) +{ + DBG("element %p name %s refcount %d", element, element->name, + g_atomic_int_get(&element->refcount) + 1); + + g_atomic_int_inc(&element->refcount); + + return element; +} + +void connman_element_unref(struct connman_element *element) +{ + DBG("element %p name %s refcount %d", element, element->name, + g_atomic_int_get(&element->refcount) - 1); + + if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) { + g_free(element->ipv4.address); + g_free(element->ipv4.netmask); + g_free(element->ipv4.gateway); + g_free(element->ipv4.network); + g_free(element->ipv4.broadcast); + g_free(element->ipv4.nameserver); + g_free(element->netdev.name); + g_free(element->info.driver); + g_free(element->info.vendor); + g_free(element->info.product); + g_free(element->path); + g_free(element->name); + g_free(element); + } +} + +int connman_element_register(struct connman_element *element, + struct connman_element *parent) +{ + GNode *node; + const gchar *basepath; + + DBG("element %p name %s parent %p", element, element->name, parent); + + if (connman_element_ref(element) == NULL) + return -1; + + g_static_mutex_lock(&element_mutex); + + if (parent) { + node = g_node_find(element_root, G_PRE_ORDER, + G_TRAVERSE_ALL, parent); + basepath = parent->path; + + if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN) + element->subtype = parent->subtype; + } else { + node = element_root; + basepath = ""; + } + + if (element->name == NULL) { + switch (element->type) { + case CONNMAN_ELEMENT_TYPE_IPV4: + element->name = g_strdup("ipv4"); + break; + case CONNMAN_ELEMENT_TYPE_IPV6: + element->name = g_strdup("ipv6"); + break; + case CONNMAN_ELEMENT_TYPE_DHCP: + element->name = g_strdup("dhcp"); + break; + case CONNMAN_ELEMENT_TYPE_BOOTP: + element->name = g_strdup("bootp"); + break; + case CONNMAN_ELEMENT_TYPE_ZEROCONF: + element->name = g_strdup("zeroconf"); + break; + default: + break; + } + } + + element->path = g_strdup_printf("%s/%s", basepath, element->name); + element->parent = parent; + + DBG("element %p path %s", element, element->path); + + g_node_append_data(node, element); + + g_static_mutex_unlock(&element_mutex); + + g_thread_pool_push(element_thread, element, NULL); + + return 0; +} + +void connman_element_unregister(struct connman_element *element) +{ + GNode *node; + + DBG("element %p name %s", element, element->name); + + g_static_mutex_lock(&element_mutex); + + if (element->driver) { + if (element->driver->remove) + element->driver->remove(element); + element->driver = NULL; + } + + node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element); + if (node != NULL) { + g_node_unlink(node); + g_node_destroy(node); + } + + g_static_mutex_unlock(&element_mutex); + + connman_element_unref(element); +} + +void connman_element_update(struct connman_element *element) +{ + DBG("element %p name %s", element, element->name); + + g_static_mutex_lock(&element_mutex); + + if (element->driver && element->driver->update) + element->driver->update(element); + + g_static_mutex_unlock(&element_mutex); +} + +static inline void set_driver(struct connman_element *element, + struct connman_driver *driver) +{ + g_static_mutex_lock(&element_mutex); + element->driver = driver; + g_static_mutex_unlock(&element_mutex); +} + +static gboolean match_driver(struct connman_element *element, + struct connman_driver *driver) +{ + if (element->type != driver->type && + driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN) + return FALSE; + + if (element->subtype == driver->subtype || + driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN) + return TRUE; + + return FALSE; +} + +static gboolean probe_driver(GNode *node, gpointer data) +{ + struct connman_element *element = node->data; + struct connman_driver *driver = data; + + DBG("element %p name %s", element, element->name); + + if (!element->driver && match_driver(element, driver) == TRUE) { + element->driver = driver; + + if (driver->probe(element) < 0) + element->driver = NULL; + } + + return FALSE; +} + +static void driver_probe(gpointer data, gpointer user_data) +{ + struct connman_driver *driver = data; + + DBG("driver %p name %s", driver, driver->name); + + g_static_mutex_lock(&element_mutex); + g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + probe_driver, driver); + g_static_mutex_unlock(&element_mutex); +} + +static void element_probe(gpointer data, gpointer user_data) +{ + struct connman_element *element = data; + GSList *list; + + DBG("element %p name %s", element, element->name); + + if (connman_element_ref(element) == NULL) + return; + + g_static_mutex_lock(&driver_mutex); + + for (list = driver_list; list; list = list->next) { + struct connman_driver *driver = list->data; + + DBG("driver %p name %s", driver, driver->name); + + set_driver(element, driver); + + if (match_driver(element, driver) == TRUE && + driver->probe(element) == 0) + break; + + set_driver(element, NULL); + } + + g_static_mutex_unlock(&driver_mutex); + + connman_element_unref(element); +} + +int __connman_element_init(void) +{ + struct connman_element *element; + + DBG(""); + + g_static_mutex_lock(&element_mutex); + + element = connman_element_create(); + + element->name = g_strdup("root"); + element->path = g_strdup("/"); + element->type = CONNMAN_ELEMENT_TYPE_ROOT; + + element_root = g_node_new(element); + + g_static_mutex_unlock(&element_mutex); + + element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL); + + driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL); + + return 0; +} + +static gboolean free_node(GNode *node, gpointer data) +{ + struct connman_element *element = node->data; + + DBG("element %p name %s", element, element->name); + + if (element->driver) { + if (element->driver->remove) + element->driver->remove(element); + element->driver = NULL; + } + + connman_element_unref(element); + + node->data = NULL; + + return FALSE; +} + +void __connman_element_cleanup(void) +{ + DBG(""); + + g_thread_pool_free(driver_thread, TRUE, TRUE); + + g_thread_pool_free(element_thread, TRUE, TRUE); + + g_static_mutex_lock(&element_mutex); + + g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1, + free_node, NULL); + + g_node_destroy(element_root); + element_root = NULL; + + g_static_mutex_unlock(&element_mutex); +} diff --git a/src/main.c b/src/main.c index 9bfb3bc..da9ba45 100644 --- a/src/main.c +++ b/src/main.c @@ -127,6 +127,8 @@ int main(int argc, char *argv[]) __connman_log_init(option_detach, option_debug); + __connman_element_init(); + __connman_agent_init(conn); __connman_manager_init(conn, option_compat); @@ -160,6 +162,8 @@ int main(int argc, char *argv[]) __connman_agent_cleanup(); + __connman_element_cleanup(); + __connman_log_cleanup(); g_dbus_cleanup_connection(conn); -- 2.7.4