OSDN Git Service

core/adapter: Track filters for discovery clients
authorJakub Pawlowski <jpawlowski@google.com>
Tue, 31 Mar 2015 07:33:27 +0000 (00:33 -0700)
committerArman Uguray <armansito@chromium.org>
Tue, 31 Mar 2015 22:13:59 +0000 (15:13 -0700)
This patch adds logic for setting, updating and deleting a discovery
filter for each client.

Note that the filter is not being used yet, the actual code that uses
it will be added in the following patches.

src/adapter.c

index ca1b2ca..e3460b2 100644 (file)
@@ -160,6 +160,7 @@ struct watch_client {
        struct btd_adapter *adapter;
        char *owner;
        guint watch;
+       struct discovery_filter *discovery_filter;
 };
 
 struct service_auth {
@@ -209,6 +210,9 @@ struct btd_adapter {
        uint8_t discovery_enable;       /* discovery enabled/disabled */
        bool discovery_suspended;       /* discovery has been suspended */
        GSList *discovery_list;         /* list of discovery clients */
+       GSList *set_filter_list;        /* list of clients that specified
+                                        * filter, but don't scan yet
+                                        */
        GSList *discovery_found;        /* list of found devices */
        guint discovery_idle_timeout;   /* timeout between discovery runs */
        guint passive_scan_timeout;     /* timeout between passive scans */
@@ -1358,6 +1362,15 @@ static uint8_t get_scan_type(struct btd_adapter *adapter)
        return type;
 }
 
+static void free_discovery_filter(struct discovery_filter *discovery_filter)
+{
+       if (!discovery_filter)
+               return;
+
+       g_slist_free_full(discovery_filter->uuids, g_free);
+       g_free(discovery_filter);
+}
+
 static void trigger_start_discovery(struct btd_adapter *adapter, guint delay);
 
 static void start_discovery_complete(uint8_t status, uint16_t length,
@@ -1657,9 +1670,17 @@ static void discovery_destroy(void *user_data)
 
        DBG("owner %s", client->owner);
 
+       adapter->set_filter_list = g_slist_remove(adapter->set_filter_list,
+                                                               client);
+
        adapter->discovery_list = g_slist_remove(adapter->discovery_list,
                                                                client);
 
+       if (client->discovery_filter) {
+               free_discovery_filter(client->discovery_filter);
+               client->discovery_filter = NULL;
+       }
+
        g_free(client->owner);
        g_free(client);
 
@@ -1696,6 +1717,9 @@ static void discovery_disconnect(DBusConnection *conn, void *user_data)
 
        DBG("owner %s", client->owner);
 
+       adapter->set_filter_list = g_slist_remove(adapter->set_filter_list,
+                                                               client);
+
        adapter->discovery_list = g_slist_remove(adapter->discovery_list,
                                                                client);
 
@@ -1729,36 +1753,75 @@ static void discovery_disconnect(DBusConnection *conn, void *user_data)
                                stop_discovery_complete, adapter, NULL);
 }
 
+/*
+ * Returns true if client was already discovering, false otherwise. *client
+ * will point to discovering client, or client that have pre-set his filter.
+ */
+static bool get_discovery_client(struct btd_adapter *adapter,
+                                               const char *owner,
+                                               struct watch_client **client)
+{
+       GSList *list = g_slist_find_custom(adapter->discovery_list, owner,
+                                                               compare_sender);
+       if (list) {
+               *client = list->data;
+               return true;
+       }
+
+       list = g_slist_find_custom(adapter->set_filter_list, owner,
+                                                               compare_sender);
+       if (list) {
+               *client = list->data;
+               return false;
+       }
+
+       *client = NULL;
+       return false;
+}
+
 static DBusMessage *start_discovery(DBusConnection *conn,
                                        DBusMessage *msg, void *user_data)
 {
        struct btd_adapter *adapter = user_data;
        const char *sender = dbus_message_get_sender(msg);
        struct watch_client *client;
-       GSList *list;
+       bool is_discovering;
 
        DBG("sender %s", sender);
 
        if (!(adapter->current_settings & MGMT_SETTING_POWERED))
                return btd_error_not_ready(msg);
 
+       is_discovering = get_discovery_client(adapter, sender, &client);
+
        /*
         * Every client can only start one discovery, if the client
         * already started a discovery then return an error.
         */
-       list = g_slist_find_custom(adapter->discovery_list, sender,
-                                               compare_sender);
-       if (list)
+       if (is_discovering)
                return btd_error_busy(msg);
 
+       /*
+        * If there was pre-set filter, just reconnect it to discovery_list,
+        * and trigger scan.
+        */
+       if (client) {
+               adapter->set_filter_list = g_slist_remove(
+                                            adapter->set_filter_list, client);
+               adapter->discovery_list = g_slist_prepend(
+                                            adapter->discovery_list, client);
+               trigger_start_discovery(adapter, 0);
+               return dbus_message_new_method_return(msg);
+       }
+
        client = g_new0(struct watch_client, 1);
 
        client->adapter = adapter;
        client->owner = g_strdup(sender);
+       client->discovery_filter = NULL;
        client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
                                                discovery_disconnect, client,
                                                discovery_destroy);
-
        adapter->discovery_list = g_slist_prepend(adapter->discovery_list,
                                                                client);
 
@@ -1951,9 +2014,10 @@ static DBusMessage *set_discovery_filter(DBusConnection *conn,
                                        DBusMessage *msg, void *user_data)
 {
        struct btd_adapter *adapter = user_data;
+       struct watch_client *client;
        struct discovery_filter *discovery_filter;
-
        const char *sender = dbus_message_get_sender(msg);
+       bool is_discovering;
 
        DBG("sender %s", sender);
 
@@ -1964,7 +2028,38 @@ static DBusMessage *set_discovery_filter(DBusConnection *conn,
        if (!parse_discovery_filter_dict(&discovery_filter, msg))
                return btd_error_invalid_args(msg);
 
-       return btd_error_failed(msg, "Not implemented yet");
+       is_discovering = get_discovery_client(adapter, sender, &client);
+
+       if (client) {
+               free_discovery_filter(client->discovery_filter);
+               client->discovery_filter = discovery_filter;
+
+               if (discovery_filter || is_discovering)
+                       return dbus_message_new_method_return(msg);
+
+               /* Removing pre-set filter */
+               adapter->set_filter_list = g_slist_remove(
+                                             adapter->set_filter_list,
+                                             client);
+               g_free(client->owner);
+               g_free(client);
+               DBG("successfully cleared pre-set filter");
+       } else if (discovery_filter) {
+               /* Client pre-setting his filter for first time */
+               client = g_new0(struct watch_client, 1);
+               client->adapter = adapter;
+               client->owner = g_strdup(sender);
+               client->discovery_filter = discovery_filter;
+               client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
+                                               discovery_disconnect, client,
+                                               discovery_destroy);
+               adapter->set_filter_list = g_slist_prepend(
+                                            adapter->set_filter_list, client);
+
+               DBG("successfully pre-set filter");
+       }
+
+       return dbus_message_new_method_return(msg);
 }
 
 static DBusMessage *stop_discovery(DBusConnection *conn,
@@ -5192,6 +5287,18 @@ static void adapter_stop(struct btd_adapter *adapter)
 
        cancel_passive_scanning(adapter);
 
+       while (adapter->set_filter_list) {
+               struct watch_client *client;
+
+               client = adapter->set_filter_list->data;
+
+               /* g_dbus_remove_watch will remove the client from the
+                * adapter's list and free it using the discovery_destroy
+                * function.
+                */
+               g_dbus_remove_watch(dbus_conn, client->watch);
+       }
+
        while (adapter->discovery_list) {
                struct watch_client *client;