Add new element infrastructure
authorMarcel Holtmann <marcel@holtmann.org>
Sat, 28 Jun 2008 08:27:57 +0000 (10:27 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Sat, 28 Jun 2008 08:27:57 +0000 (10:27 +0200)
include/Makefile.am
include/driver.h [new file with mode: 0644]
include/element.h [new file with mode: 0644]
src/Makefile.am
src/connman.h
src/element.c [new file with mode: 0644]
src/main.c

index 15af374..e2dacdc 100644 (file)
@@ -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 (file)
index 0000000..3d0ad92
--- /dev/null
@@ -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 <connman/element.h>
+
+#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 (file)
index 0000000..dfcbd0f
--- /dev/null
@@ -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 <errno.h>
+#include <glib.h>
+
+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 */
index 1f585c7..1ab7d7a 100644 (file)
@@ -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
 
index e04ddf5..e4f51df 100644 (file)
@@ -47,6 +47,14 @@ void __connman_log_cleanup(void);
 int __connman_plugin_init(void);
 void __connman_plugin_cleanup(void);
 
+#include <connman/driver.h>
+#include <connman/element.h>
+
+int __connman_element_init(void);
+void __connman_element_cleanup(void);
+
+void __connman_element_list(DBusMessageIter *iter);
+
 #include <connman/iface.h>
 
 int __connman_iface_init(DBusConnection *conn, const char *interface);
diff --git a/src/element.c b/src/element.c
new file mode 100644 (file)
index 0000000..71332d0
--- /dev/null
@@ -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 <config.h>
+#endif
+
+#include <errno.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#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);
+}
index 9bfb3bc..da9ba45 100644 (file)
@@ -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);