Add service initialization and lifetime tracking support
authorMarcel Holtmann <marcel@holtmann.org>
Tue, 7 Apr 2009 23:54:19 +0000 (16:54 -0700)
committerMarcel Holtmann <marcel@holtmann.org>
Wed, 8 Apr 2009 04:02:48 +0000 (21:02 -0700)
include/service.h
src/connman.h
src/element.c
src/service.c

index 9e97cf6..e83911c 100644 (file)
@@ -65,6 +65,9 @@ enum connman_service_state {
 
 struct connman_service;
 
+extern struct connman_service *connman_service_get(const char *identifier);
+extern void connman_service_put(struct connman_service *service);
+
 #ifdef __cplusplus
 }
 #endif
index 44cba11..a97dfad 100644 (file)
@@ -209,6 +209,9 @@ int __connman_profile_remove_network(struct connman_network *network);
 
 #include <connman/service.h>
 
+int __connman_service_init(void);
+void __connman_service_cleanup(void);
+
 #include <connman/notifier.h>
 
 int __connman_notifier_init(void);
index b68e954..7b24a98 100644 (file)
@@ -1284,6 +1284,7 @@ int __connman_element_init(DBusConnection *conn, const char *device,
        element_root = g_node_new(element);
 
        __connman_notifier_init();
+       __connman_service_init();
        __connman_network_init();
        __connman_device_init();
 
@@ -1368,6 +1369,7 @@ void __connman_element_cleanup(void)
 
        __connman_device_cleanup();
        __connman_network_cleanup();
+       __connman_service_cleanup();
        __connman_notifier_cleanup();
 
        g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
index f272fe3..9c95fc6 100644 (file)
 
 #include "connman.h"
 
+static DBusConnection *connection = NULL;
+
+static GSequence *service_list = NULL;
+static GHashTable *service_hash = NULL;
+
 struct connman_service {
+       gint refcount;
+       char *identifier;
        char *path;
        enum connman_service_type type;
        enum connman_service_mode mode;
@@ -35,3 +42,104 @@ struct connman_service {
        connman_bool_t favorite;
        char *name;
 };
+
+static void service_free(gpointer data)
+{
+       struct connman_service *service = data;
+
+       DBG("service %p", service);
+
+       g_hash_table_remove(service_hash, service->identifier);
+
+       g_free(service->name);
+       g_free(service->path);
+       g_free(service->identifier);
+       g_free(service);
+}
+
+static gint service_compare(gconstpointer a, gconstpointer b,
+                                                       gpointer user_data)
+{
+       struct connman_service *service_a = (void *) a;
+       struct connman_service *service_b = (void *) b;
+
+       if (service_a->favorite == TRUE && service_b->favorite == FALSE)
+               return -1;
+
+       if (service_a->favorite == FALSE && service_b->favorite == TRUE)
+               return 1;
+
+       return (gint) service_b->strength - (gint) service_a->strength;
+}
+
+struct connman_service *connman_service_get(const char *identifier)
+{
+       struct connman_service *service;
+       GSequenceIter *iter;
+
+       iter = g_hash_table_lookup(service_hash, identifier);
+       if (iter != NULL) {
+               service = g_sequence_get(iter);
+               if (service != NULL)
+                       g_atomic_int_inc(&service->refcount);
+               return service;
+       }
+
+       service = g_try_new0(struct connman_service, 1);
+       if (service == NULL)
+               return NULL;
+
+       DBG("service %p", service);
+
+       service->refcount = 1;
+       service->identifier = g_strdup(identifier);
+
+       iter = g_sequence_insert_sorted(service_list, service,
+                                                service_compare, NULL);
+
+       g_hash_table_insert(service_hash, service->identifier, iter);
+
+       return service;
+}
+
+void connman_service_put(struct connman_service *service)
+{
+       DBG("service %p", service);
+
+       if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
+               GSequenceIter *iter;
+
+               iter = g_hash_table_lookup(service_hash, service->identifier);
+               if (iter != NULL)
+                       g_sequence_remove(iter);
+               else
+                       service_free(service);
+       }
+}
+
+int __connman_service_init(void)
+{
+       DBG("");
+
+       connection = connman_dbus_get_connection();
+
+       service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                               NULL, NULL);
+
+       service_list = g_sequence_new(service_free);
+
+       return 0;
+}
+
+void __connman_service_cleanup(void)
+{
+       DBG("");
+
+       g_sequence_free(service_list);
+       service_list = NULL;
+
+       g_hash_table_destroy(service_hash);
+       service_hash = NULL;
+
+       dbus_connection_unref(connection);
+}