X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Felement.c;h=6086b7b15970dca5514b40287fb96170660ca810;hb=004cbb420e7a2b44cb2fde3b9e37f9dc3e60067e;hp=58ba06babcd1dd700359587767668715148f8c9a;hpb=a76452265e0d73fed9d2ad591863b231df30292d;p=connman diff --git a/src/element.c b/src/element.c index 58ba06b..6086b7b 100644 --- a/src/element.c +++ b/src/element.c @@ -32,13 +32,15 @@ static DBusConnection *connection; -static GStaticRWLock driver_lock = G_STATIC_RW_LOCK_INIT; -static GSList *driver_list = NULL; -static GThreadPool *driver_thread; - static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT; static GNode *element_root = NULL; -static GThreadPool *element_thread; + +static GSList *driver_list = NULL; + +static GThreadPool *thread_register = NULL; +static GThreadPool *thread_unregister = NULL; + +static gchar *device_filter = NULL; static const char *type2string(enum connman_element_type type) { @@ -61,8 +63,10 @@ static const char *type2string(enum connman_element_type type) return "bootp"; case CONNMAN_ELEMENT_TYPE_ZEROCONF: return "zeroconf"; - case CONNMAN_ELEMENT_TYPE_CONNECTION: - return "42"; + case CONNMAN_ELEMENT_TYPE_RESOLVER: + return "resolver"; + case CONNMAN_ELEMENT_TYPE_INTERNET: + return "internet"; } return NULL; @@ -100,6 +104,9 @@ static void append_entry(DBusMessageIter *dict, dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); switch (type) { + case DBUS_TYPE_BOOLEAN: + signature = DBUS_TYPE_BOOLEAN_AS_STRING; + break; case DBUS_TYPE_STRING: signature = DBUS_TYPE_STRING_AS_STRING; break; @@ -168,10 +175,17 @@ static DBusMessage *get_properties(DBusConnection *conn, if (str != NULL) append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str); + append_entry(&dict, "Connected", + DBUS_TYPE_BOOLEAN, &element->connected); + if (element->priority > 0) append_entry(&dict, "Priority", DBUS_TYPE_UINT16, &element->priority); + if (element->network.identifier != NULL) + append_entry(&dict, "Identifier", + DBUS_TYPE_STRING, &element->network.identifier); + if (element->ipv4.address != NULL) append_entry(&dict, "IPv4.Address", DBUS_TYPE_STRING, &element->ipv4.address); @@ -193,8 +207,77 @@ static DBusMessage *get_properties(DBusConnection *conn, return reply; } +static DBusMessage *set_property(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static DBusMessage *do_update(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct connman_element *element = data; + + DBG("conn %p", conn); + + if (element->driver == NULL) + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + + if (element->driver->update) { + DBG("Calling update callback"); + element->driver->update(element); + } + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static DBusMessage *do_connect(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct connman_element *element = data; + + DBG("conn %p", conn); + + if (element->driver == NULL) + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + + if (element->driver->connect) { + DBG("Calling connect callback"); + element->driver->connect(element); + } + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static DBusMessage *do_disconnect(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct connman_element *element = data; + + DBG("conn %p", conn); + + if (element->driver == NULL) + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + + if (element->driver->disconnect) { + DBG("Calling disconnect callback"); + element->driver->disconnect(element); + } + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + static GDBusMethodTable element_methods[] = { - { "GetProperties", "", "a{sv}", get_properties }, + { "GetProperties", "", "a{sv}", get_properties }, + { "SetProperty", "sv", "", set_property }, + { "Update", "", "", do_update }, + { "Connect", "", "", do_connect }, + { "Disconnect", "", "", do_disconnect }, + { }, +}; + +static GDBusSignalTable element_signals[] = { + { "PropertyChanged", "sv" }, { }, }; @@ -244,22 +327,62 @@ static gint compare_priority(gconstpointer a, gconstpointer b) return driver2->priority - driver1->priority; } +static gboolean match_driver(struct connman_element *element, + struct connman_driver *driver) +{ + if (element->type == CONNMAN_ELEMENT_TYPE_ROOT) + return FALSE; + + 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) { + if (driver->probe(element) < 0) + return FALSE; + + connman_element_lock(element); + element->driver = driver; + connman_element_unlock(element); + } + + return FALSE; +} + 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; + return -EINVAL; if (!driver->probe) return -EINVAL; - g_static_rw_lock_writer_lock(&driver_lock); + g_static_rw_lock_writer_lock(&element_lock); + driver_list = g_slist_insert_sorted(driver_list, driver, compare_priority); - g_static_rw_lock_writer_unlock(&driver_lock); - g_thread_pool_push(driver_thread, driver, NULL); + if (element_root != NULL) + g_node_traverse(element_root, G_PRE_ORDER, + G_TRAVERSE_ALL, -1, probe_driver, driver); + + g_static_rw_lock_writer_unlock(&element_lock); return 0; } @@ -274,7 +397,10 @@ static gboolean remove_driver(GNode *node, gpointer data) if (element->driver == driver) { if (driver->remove) driver->remove(element); + + connman_element_lock(element); element->driver = NULL; + connman_element_unlock(element); } return FALSE; @@ -284,14 +410,15 @@ void connman_driver_unregister(struct connman_driver *driver) { DBG("driver %p name %s", driver, driver->name); - g_static_rw_lock_reader_lock(&element_lock); - g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1, - remove_driver, driver); - g_static_rw_lock_reader_unlock(&element_lock); + g_static_rw_lock_writer_lock(&element_lock); - g_static_rw_lock_writer_lock(&driver_lock); driver_list = g_slist_remove(driver_list, driver); - g_static_rw_lock_writer_unlock(&driver_lock); + + if (element_root != NULL) + g_node_traverse(element_root, G_POST_ORDER, + G_TRAVERSE_ALL, -1, remove_driver, driver); + + g_static_rw_lock_writer_unlock(&element_lock); } struct connman_element *connman_element_create(void) @@ -304,10 +431,14 @@ struct connman_element *connman_element_create(void) element->refcount = 1; + g_static_mutex_init(&element->mutex); + element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN; element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN; element->state = CONNMAN_ELEMENT_STATE_CLOSED; + element->connected = FALSE; + element->netdev.index = -1; return element; @@ -347,6 +478,7 @@ void connman_element_unref(struct connman_element *element) g_free(element->ipv4.network); g_free(element->ipv4.broadcast); g_free(element->ipv4.nameserver); + g_free(element->network.identifier); g_free(element->netdev.name); g_free(element->path); g_free(element->name); @@ -381,7 +513,9 @@ int connman_element_add_static_property(struct connman_element *element, break; } + connman_element_lock(element); element->properties = g_slist_append(element->properties, property); + connman_element_unlock(element); return 0; } @@ -393,16 +527,28 @@ int connman_element_set_property(struct connman_element *element, case CONNMAN_PROPERTY_TYPE_INVALID: return -EINVAL; case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS: + connman_element_lock(element); g_free(element->ipv4.address); element->ipv4.address = g_strdup(*((const char **) value)); + connman_element_unlock(element); break; case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK: + connman_element_lock(element); g_free(element->ipv4.netmask); element->ipv4.netmask = g_strdup(*((const char **) value)); + connman_element_unlock(element); break; case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY: + connman_element_lock(element); g_free(element->ipv4.gateway); element->ipv4.gateway = g_strdup(*((const char **) value)); + connman_element_unlock(element); + break; + case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER: + connman_element_lock(element); + g_free(element->ipv4.nameserver); + element->ipv4.nameserver = g_strdup(*((const char **) value)); + connman_element_unlock(element); break; } @@ -427,19 +573,33 @@ int connman_element_get_value(struct connman_element *element, if (element->ipv4.address == NULL) return connman_element_get_value(element->parent, type, value); + connman_element_lock(element); *((char **) value) = element->ipv4.address; + connman_element_unlock(element); break; case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK: if (element->ipv4.netmask == NULL) return connman_element_get_value(element->parent, type, value); + connman_element_lock(element); *((char **) value) = element->ipv4.netmask; + connman_element_unlock(element); break; case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY: if (element->ipv4.gateway == NULL) return connman_element_get_value(element->parent, type, value); + connman_element_lock(element); *((char **) value) = element->ipv4.gateway; + connman_element_unlock(element); + break; + case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER: + if (element->ipv4.nameserver == NULL) + return connman_element_get_value(element->parent, + type, value); + connman_element_lock(element); + *((char **) value) = element->ipv4.nameserver; + connman_element_unlock(element); break; } @@ -449,29 +609,19 @@ int connman_element_get_value(struct connman_element *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; + if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) { + if (g_str_equal(device_filter, element->netdev.name) == FALSE) + return -EINVAL; + } - __connman_element_load(element); + if (connman_element_ref(element) == NULL) + return -EINVAL; - g_static_rw_lock_writer_lock(&element_lock); + connman_element_lock(element); - 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 = ""; - } + __connman_element_load(element); if (element->name == NULL) { switch (element->type) { @@ -490,182 +640,171 @@ int connman_element_register(struct connman_element *element, case CONNMAN_ELEMENT_TYPE_ZEROCONF: element->name = g_strdup("zeroconf"); break; + case CONNMAN_ELEMENT_TYPE_RESOLVER: + element->name = g_strdup("resolver"); + break; + case CONNMAN_ELEMENT_TYPE_INTERNET: + element->name = g_strdup("internet"); + break; default: break; } } - element->path = g_strdup_printf("%s/%s", basepath, element->name); element->parent = parent; - DBG("element %p path %s", element, element->path); + connman_element_unlock(element); - g_node_append_data(node, element); - - g_static_rw_lock_writer_unlock(&element_lock); - - __connman_element_store(element); - - g_dbus_register_interface(connection, element->path, - CONNMAN_ELEMENT_INTERFACE, - element_methods, NULL, NULL, - element, NULL); - - g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "ElementAdded", - DBUS_TYPE_OBJECT_PATH, &element->path, - DBUS_TYPE_INVALID); - - if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE) - g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "DeviceAdded", - DBUS_TYPE_OBJECT_PATH, &element->path, - DBUS_TYPE_INVALID); - - g_thread_pool_push(element_thread, element, NULL); + if (thread_register != NULL) + g_thread_pool_push(thread_register, element, NULL); return 0; } void connman_element_unregister(struct connman_element *element) { - GNode *node; + DBG("element %p name %s", element, element->name); + + if (thread_unregister != NULL) + g_thread_pool_push(thread_unregister, element, NULL); +} +void connman_element_update(struct connman_element *element) +{ DBG("element %p name %s", element, element->name); - if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE) - g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "DeviceRemoved", - DBUS_TYPE_OBJECT_PATH, &element->path, - DBUS_TYPE_INVALID); + g_static_rw_lock_reader_lock(&element_lock); + + if (element->driver && element->driver->update) + element->driver->update(element); + + g_static_rw_lock_reader_unlock(&element_lock); g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "ElementRemoved", + CONNMAN_MANAGER_INTERFACE, "ElementUpdated", DBUS_TYPE_OBJECT_PATH, &element->path, DBUS_TYPE_INVALID); +} - g_dbus_unregister_interface(connection, element->path, - CONNMAN_ELEMENT_INTERFACE); +static void register_element(gpointer data, gpointer user_data) +{ + struct connman_element *element = data; + const gchar *basepath; + GSList *list; + GNode *node; g_static_rw_lock_writer_lock(&element_lock); - if (element->driver) { - if (element->driver->remove) - element->driver->remove(element); - element->driver = NULL; - } + connman_element_lock(element); - node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element); - if (node != NULL) { - g_node_unlink(node); - g_node_destroy(node); - } + if (element->parent) { + node = g_node_find(element_root, G_PRE_ORDER, + G_TRAVERSE_ALL, element->parent); + basepath = element->parent->path; - g_static_rw_lock_writer_unlock(&element_lock); + if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN) + element->subtype = element->parent->subtype; + } else { + node = element_root; + basepath = ""; + } - connman_element_unref(element); -} + element->path = g_strdup_printf("%s/%s", basepath, element->name); -void connman_element_update(struct connman_element *element) -{ - DBG("element %p name %s", element, element->name); + connman_element_unlock(element); - g_static_rw_lock_reader_lock(&element_lock); + DBG("element %p path %s", element, element->path); - if (element->driver && element->driver->update) - element->driver->update(element); + g_node_append_data(node, element); - g_static_rw_lock_reader_unlock(&element_lock); + if (g_dbus_register_interface(connection, element->path, + CONNMAN_ELEMENT_INTERFACE, + element_methods, element_signals, + NULL, element, NULL) == FALSE) + connman_error("Failed to register %s", element->path); g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "ElementUpdated", + CONNMAN_MANAGER_INTERFACE, "ElementAdded", DBUS_TYPE_OBJECT_PATH, &element->path, DBUS_TYPE_INVALID); -} -static inline void set_driver(struct connman_element *element, - struct connman_driver *driver) -{ - g_static_rw_lock_reader_lock(&element_lock); - element->driver = driver; - g_static_rw_lock_reader_unlock(&element_lock); -} + g_static_rw_lock_writer_unlock(&element_lock); -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; + __connman_element_store(element); - if (element->subtype == driver->subtype || - driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN) - return TRUE; + g_static_rw_lock_writer_lock(&element_lock); - return FALSE; + for (list = driver_list; list; list = list->next) { + struct connman_driver *driver = list->data; + + if (match_driver(element, driver) == FALSE) + continue; + + DBG("driver %p name %s", driver, driver->name); + + if (driver->probe(element) < 0) + continue; + + connman_element_lock(element); + element->driver = driver; + connman_element_unlock(element); + } + + g_static_rw_lock_writer_unlock(&element_lock); } -static gboolean probe_driver(GNode *node, gpointer data) +static gboolean remove_element(GNode *node, gpointer user_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 (element->driver) { + if (element->driver->remove) + element->driver->remove(element); - if (driver->probe(element) < 0) - element->driver = NULL; + connman_element_lock(element); + element->driver = NULL; + connman_element_unlock(element); } - return FALSE; -} + if (node != NULL) { + g_node_unlink(node); + g_node_destroy(node); + } -static void driver_probe(gpointer data, gpointer user_data) -{ - struct connman_driver *driver = data; + g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE, "ElementRemoved", + DBUS_TYPE_OBJECT_PATH, &element->path, + DBUS_TYPE_INVALID); - DBG("driver %p name %s", driver, driver->name); + g_dbus_unregister_interface(connection, element->path, + CONNMAN_ELEMENT_INTERFACE); - g_static_rw_lock_reader_lock(&element_lock); - g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - probe_driver, driver); - g_static_rw_lock_reader_unlock(&element_lock); + connman_element_unref(element); + + return FALSE; } -static void element_probe(gpointer data, gpointer user_data) +static void unregister_element(gpointer data, gpointer user_data) { struct connman_element *element = data; - GSList *list; + GNode *node; DBG("element %p name %s", element, element->name); - if (connman_element_ref(element) == NULL) - return; - - g_static_rw_lock_reader_lock(&driver_lock); - - 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; + g_static_rw_lock_writer_lock(&element_lock); - set_driver(element, NULL); - } + node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element); - g_static_rw_lock_reader_unlock(&driver_lock); + if (node != NULL) + g_node_traverse(node, G_POST_ORDER, + G_TRAVERSE_ALL, -1, remove_element, NULL); - connman_element_unref(element); + g_static_rw_lock_writer_unlock(&element_lock); } -int __connman_element_init(DBusConnection *conn) +int __connman_element_init(DBusConnection *conn, const char *device) { struct connman_element *element; @@ -675,6 +814,8 @@ int __connman_element_init(DBusConnection *conn) if (connection == NULL) return -EIO; + device_filter = g_strdup(device); + g_static_rw_lock_writer_lock(&element_lock); element = connman_element_create(); @@ -687,31 +828,40 @@ int __connman_element_init(DBusConnection *conn) g_static_rw_lock_writer_unlock(&element_lock); - element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL); - - driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL); + thread_register = g_thread_pool_new(register_element, + NULL, 1, FALSE, NULL); + thread_unregister = g_thread_pool_new(unregister_element, + NULL, 1, FALSE, NULL); return 0; } -static gboolean free_node(GNode *node, gpointer data) +static gboolean free_driver(GNode *node, gpointer data) { struct connman_element *element = node->data; DBG("element %p name %s", element, element->name); - g_dbus_unregister_interface(connection, element->path, - CONNMAN_ELEMENT_INTERFACE); - if (element->driver) { if (element->driver->remove) element->driver->remove(element); + + connman_element_lock(element); element->driver = NULL; + connman_element_unlock(element); } - connman_element_unref(element); + return FALSE; +} + +static gboolean free_node(GNode *node, gpointer data) +{ + struct connman_element *element = node->data; + + DBG("element %p name %s", element, element->name); - node->data = NULL; + if (g_node_depth(node) > 1) + g_thread_pool_push(thread_unregister, element, NULL); return FALSE; } @@ -720,19 +870,28 @@ void __connman_element_cleanup(void) { DBG(""); - g_thread_pool_free(driver_thread, TRUE, TRUE); - - g_thread_pool_free(element_thread, TRUE, TRUE); + g_thread_pool_free(thread_register, TRUE, TRUE); + thread_register = NULL; g_static_rw_lock_writer_lock(&element_lock); + g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1, + free_driver, NULL); + g_static_rw_lock_writer_unlock(&element_lock); + g_static_rw_lock_writer_lock(&element_lock); g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1, free_node, NULL); + g_static_rw_lock_writer_unlock(&element_lock); + g_thread_pool_free(thread_unregister, FALSE, TRUE); + thread_unregister = NULL; + + g_static_rw_lock_writer_lock(&element_lock); g_node_destroy(element_root); element_root = NULL; - g_static_rw_lock_writer_unlock(&element_lock); + g_free(device_filter); + dbus_connection_unref(connection); }