[PATCH BlueZ v2] client: Add better support for managing devices of multiple controllers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Previously devices list was cleared when selecting new default
controller. Now devices list is preserverd allowing to list and suggest
devices for default controller even after changing the default
controller.
---
 Makefile.tools |   2 +-
 client/main.c  | 261 +++++++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 189 insertions(+), 74 deletions(-)

diff --git a/Makefile.tools b/Makefile.tools
index 0d5f143..11fb60e 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -8,7 +8,7 @@ client_bluetoothctl_SOURCES = client/main.c \
 					client/gatt.h client/gatt.c \
 					monitor/uuid.h monitor/uuid.c
 client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@ \
-				-lreadline
+				-lreadline src/libshared-mainloop.la
 endif
 
 if MONITOR
diff --git a/client/main.c b/client/main.c
index 056331f..59baa1d 100644
--- a/client/main.c
+++ b/client/main.c
@@ -43,6 +43,7 @@
 #include "agent.h"
 #include "display.h"
 #include "gatt.h"
+#include "src/shared/util.h"
 
 /* String display constants */
 #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
@@ -58,11 +59,15 @@ static DBusConnection *dbus_conn;
 static GDBusProxy *agent_manager;
 static char *auto_register_agent = NULL;
 
-static GDBusProxy *default_ctrl;
+struct adapter {
+	GDBusProxy *proxy;
+	GList *devices;
+};
+
+static struct adapter *default_ctrl;
 static GDBusProxy *default_dev;
 static GDBusProxy *default_attr;
 static GList *ctrl_list;
-static GList *dev_list;
 
 static guint input = 0;
 
@@ -134,13 +139,10 @@ static void disconnect_handler(DBusConnection *connection, void *user_data)
 	rl_on_new_line();
 	rl_redisplay();
 
-	g_list_free(ctrl_list);
+	g_list_free_full(ctrl_list, proxy_leak);
 	ctrl_list = NULL;
 
 	default_ctrl = NULL;
-
-	g_list_free(dev_list);
-	dev_list = NULL;
 }
 
 static void print_adapter(GDBusProxy *proxy, const char *description)
@@ -163,7 +165,7 @@ static void print_adapter(GDBusProxy *proxy, const char *description)
 				description ? : "",
 				description ? "] " : "",
 				address, name,
-				default_ctrl == proxy ? "[default]" : "");
+				default_ctrl && default_ctrl->proxy == proxy ? "[default]" : "");
 
 }
 
@@ -346,10 +348,13 @@ static gboolean service_is_child(GDBusProxy *service)
 
 	dbus_message_iter_get_basic(&iter, &device);
 
-	for (l = dev_list; l; l = g_list_next(l)) {
-		GDBusProxy *proxy = l->data;
+	if (!default_ctrl)
+		return FALSE;
+
+	for (l = default_ctrl->devices; l; l = g_list_next(l)) {
+		struct adapter *adapter = l->data;
 
-		path = g_dbus_proxy_get_path(proxy);
+		path = g_dbus_proxy_get_path(adapter->proxy);
 
 		if (!strcmp(path, device))
 			return TRUE;
@@ -358,6 +363,19 @@ static gboolean service_is_child(GDBusProxy *service)
 	return FALSE;
 }
 
+static struct adapter *find_parent(GDBusProxy *device)
+{
+	GList *list;
+
+	for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
+		struct adapter *adapter = list->data;
+
+		if (device_is_child(device, adapter->proxy) == TRUE) 
+			return adapter;
+	}
+	return NULL;
+}
+
 static void set_default_device(GDBusProxy *proxy, const char *attribute)
 {
 	char *desc = NULL;
@@ -394,8 +412,13 @@ static void device_added(GDBusProxy *proxy)
 {
 	DBusMessageIter iter;
 
-	dev_list = g_list_append(dev_list, proxy);
+	struct adapter *adapter = find_parent(proxy);
+	if (!adapter) {
+		/* TODO: Error */
+		return;
+	}
 
+	adapter->devices = g_list_append(adapter->devices, proxy);
 	print_device(proxy, COLORED_NEW);
 
 	if (default_dev)
@@ -411,6 +434,19 @@ static void device_added(GDBusProxy *proxy)
 	}
 }
 
+static void adapter_added(GDBusProxy *proxy)
+{
+	struct adapter *adapter = new0(struct adapter, 1);
+
+	adapter->proxy = proxy;
+	ctrl_list = g_list_append(ctrl_list, adapter);
+
+	if (!default_ctrl)
+		default_ctrl = adapter;
+
+	print_adapter(proxy, COLORED_NEW);
+}
+
 static void proxy_added(GDBusProxy *proxy, void *user_data)
 {
 	const char *interface;
@@ -418,16 +454,9 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
 	interface = g_dbus_proxy_get_interface(proxy);
 
 	if (!strcmp(interface, "org.bluez.Device1")) {
-		if (device_is_child(proxy, default_ctrl) == TRUE)
-			device_added(proxy);
-
+		device_added(proxy);
 	} else if (!strcmp(interface, "org.bluez.Adapter1")) {
-		ctrl_list = g_list_append(ctrl_list, proxy);
-
-		if (!default_ctrl)
-			default_ctrl = proxy;
-
-		print_adapter(proxy, COLORED_NEW);
+		adapter_added(proxy);
 	} else if (!strcmp(interface, "org.bluez.AgentManager1")) {
 		if (!agent_manager) {
 			agent_manager = proxy;
@@ -459,33 +488,56 @@ static void set_default_attribute(GDBusProxy *proxy)
 	set_default_device(default_dev, path);
 }
 
-static void proxy_removed(GDBusProxy *proxy, void *user_data)
+static void device_removed(GDBusProxy *proxy)
 {
-	const char *interface;
+	struct adapter *adapter = find_parent(proxy);
+	if (!adapter) {
+		/* TODO: Error */
+		return;
+	}
 
-	interface = g_dbus_proxy_get_interface(proxy);
+	adapter->devices = g_list_remove(adapter->devices, proxy);
 
-	if (!strcmp(interface, "org.bluez.Device1")) {
-		if (device_is_child(proxy, default_ctrl) == TRUE) {
-			dev_list = g_list_remove(dev_list, proxy);
+	print_device(proxy, COLORED_DEL);
+
+	if (default_dev == proxy)
+		set_default_device(NULL, NULL);
+}
 
-			print_device(proxy, COLORED_DEL);
+static void adapter_removed(GDBusProxy *proxy)
+{
+	GList *llink;
+
+	for (llink = g_list_first(ctrl_list); llink; llink = g_list_next(llink)) {
+		struct adapter *adapter = llink->data;
 
-			if (default_dev == proxy)
+		if (adapter->proxy == proxy) {
+			print_adapter(proxy, COLORED_DEL);
+
+			if (default_ctrl && default_ctrl->proxy == proxy) {
+				default_ctrl = NULL;
 				set_default_device(NULL, NULL);
+			}
+
+			ctrl_list = g_list_remove_link(ctrl_list, llink);
+			g_list_free(adapter->devices);
+			free(adapter);
+			g_list_free(llink);
+			return;
 		}
-	} else if (!strcmp(interface, "org.bluez.Adapter1")) {
-		ctrl_list = g_list_remove(ctrl_list, proxy);
+	}
+}
 
-		print_adapter(proxy, COLORED_DEL);
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+	const char *interface;
 
-		if (default_ctrl == proxy) {
-			default_ctrl = NULL;
-			set_default_device(NULL, NULL);
+	interface = g_dbus_proxy_get_interface(proxy);
 
-			g_list_free(dev_list);
-			dev_list = NULL;
-		}
+	if (!strcmp(interface, "org.bluez.Device1")) {
+		device_removed(proxy);
+	} else if (!strcmp(interface, "org.bluez.Adapter1")) {
+		adapter_removed(proxy);
 	} else if (!strcmp(interface, "org.bluez.AgentManager1")) {
 		if (agent_manager == proxy) {
 			agent_manager = NULL;
@@ -520,7 +572,7 @@ static void property_changed(GDBusProxy *proxy, const char *name,
 	interface = g_dbus_proxy_get_interface(proxy);
 
 	if (!strcmp(interface, "org.bluez.Device1")) {
-		if (device_is_child(proxy, default_ctrl) == TRUE) {
+		if (default_ctrl && device_is_child(proxy, default_ctrl->proxy) == TRUE) {
 			DBusMessageIter addr_iter;
 			char *str;
 
@@ -583,6 +635,27 @@ static void message_handler(DBusConnection *connection,
 					dbus_message_get_member(message));
 }
 
+static struct adapter *find_ctrl_by_address(GList *source, const char *address)
+{
+	GList *list;
+
+	for (list = g_list_first(source); list; list = g_list_next(list)) {
+		struct adapter *adapter = list->data;
+		DBusMessageIter iter;
+		const char *str;
+
+		if (g_dbus_proxy_get_property(adapter->proxy, "Address", &iter) == FALSE)
+			continue;
+
+		dbus_message_iter_get_basic(&iter, &str);
+
+		if (!strcmp(str, address))
+			return adapter;
+	}
+
+	return NULL;
+}
+
 static GDBusProxy *find_proxy_by_address(GList *source, const char *address)
 {
 	GList *list;
@@ -673,13 +746,14 @@ static void cmd_list(const char *arg)
 	GList *list;
 
 	for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
-		GDBusProxy *proxy = list->data;
-		print_adapter(proxy, NULL);
+		struct adapter *adapter = list->data;
+		print_adapter(adapter->proxy, NULL);
 	}
 }
 
 static void cmd_show(const char *arg)
 {
+	struct adapter *adapter;
 	GDBusProxy *proxy;
 	DBusMessageIter iter;
 	const char *address;
@@ -688,13 +762,14 @@ static void cmd_show(const char *arg)
 		if (check_default_ctrl() == FALSE)
 			return;
 
-		proxy = default_ctrl;
+		proxy = default_ctrl->proxy;
 	} else {
-		proxy = find_proxy_by_address(ctrl_list, arg);
-		if (!proxy) {
+		adapter = find_ctrl_by_address(ctrl_list, arg);
+		if (!adapter) {
 			rl_printf("Controller %s not available\n", arg);
 			return;
 		}
+		proxy = adapter->proxy;
 	}
 
 	if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
@@ -716,34 +791,34 @@ static void cmd_show(const char *arg)
 
 static void cmd_select(const char *arg)
 {
-	GDBusProxy *proxy;
+	struct adapter *adapter;
 
 	if (!arg || !strlen(arg)) {
 		rl_printf("Missing controller address argument\n");
 		return;
 	}
 
-	proxy = find_proxy_by_address(ctrl_list, arg);
-	if (!proxy) {
+	adapter = find_ctrl_by_address(ctrl_list, arg);
+	if (!adapter) {
 		rl_printf("Controller %s not available\n", arg);
 		return;
 	}
 
-	if (default_ctrl == proxy)
+	if (default_ctrl && default_ctrl->proxy == adapter->proxy)
 		return;
 
-	default_ctrl = proxy;
-	print_adapter(proxy, NULL);
-
-	g_list_free(dev_list);
-	dev_list = NULL;
+	default_ctrl = adapter;
+	print_adapter(adapter->proxy, NULL);
 }
 
 static void cmd_devices(const char *arg)
 {
 	GList *list;
 
-	for (list = g_list_first(dev_list); list; list = g_list_next(list)) {
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	for (list = g_list_first(default_ctrl->devices); list; list = g_list_next(list)) {
 		GDBusProxy *proxy = list->data;
 		print_device(proxy, NULL);
 	}
@@ -753,7 +828,10 @@ static void cmd_paired_devices(const char *arg)
 {
 	GList *list;
 
-	for (list = g_list_first(dev_list); list; list = g_list_next(list)) {
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	for (list = g_list_first(default_ctrl->devices); list; list = g_list_next(list)) {
 		GDBusProxy *proxy = list->data;
 		DBusMessageIter iter;
 		dbus_bool_t paired;
@@ -793,7 +871,7 @@ static void cmd_system_alias(const char *arg)
 
 	name = g_strdup(arg);
 
-	if (g_dbus_proxy_set_property_basic(default_ctrl, "Alias",
+	if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Alias",
 					DBUS_TYPE_STRING, &name,
 					generic_callback, name, g_free) == TRUE)
 		return;
@@ -810,7 +888,7 @@ static void cmd_reset_alias(const char *arg)
 
 	name = g_strdup("");
 
-	if (g_dbus_proxy_set_property_basic(default_ctrl, "Alias",
+	if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Alias",
 					DBUS_TYPE_STRING, &name,
 					generic_callback, name, g_free) == TRUE)
 		return;
@@ -831,7 +909,7 @@ static void cmd_power(const char *arg)
 
 	str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
 
-	if (g_dbus_proxy_set_property_basic(default_ctrl, "Powered",
+	if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Powered",
 					DBUS_TYPE_BOOLEAN, &powered,
 					generic_callback, str, g_free) == TRUE)
 		return;
@@ -852,7 +930,7 @@ static void cmd_pairable(const char *arg)
 
 	str = g_strdup_printf("pairable %s", pairable == TRUE ? "on" : "off");
 
-	if (g_dbus_proxy_set_property_basic(default_ctrl, "Pairable",
+	if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Pairable",
 					DBUS_TYPE_BOOLEAN, &pairable,
 					generic_callback, str, g_free) == TRUE)
 		return;
@@ -874,7 +952,7 @@ static void cmd_discoverable(const char *arg)
 	str = g_strdup_printf("discoverable %s",
 				discoverable == TRUE ? "on" : "off");
 
-	if (g_dbus_proxy_set_property_basic(default_ctrl, "Discoverable",
+	if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Discoverable",
 					DBUS_TYPE_BOOLEAN, &discoverable,
 					generic_callback, str, g_free) == TRUE)
 		return;
@@ -948,7 +1026,7 @@ static void cmd_scan(const char *arg)
 	else
 		method = "StopDiscovery";
 
-	if (g_dbus_proxy_method_call(default_ctrl, method,
+	if (g_dbus_proxy_method_call(default_ctrl->proxy, method,
 				NULL, start_discovery_reply,
 				GUINT_TO_POINTER(enable), NULL) == FALSE) {
 		rl_printf("Failed to %s discovery\n",
@@ -1117,7 +1195,7 @@ static void cmd_set_scan_filter_commit(void)
 	if (check_default_ctrl() == FALSE)
 		return;
 
-	if (g_dbus_proxy_method_call(default_ctrl, "SetDiscoveryFilter",
+	if (g_dbus_proxy_method_call(default_ctrl->proxy, "SetDiscoveryFilter",
 		set_discovery_filter_setup, set_discovery_filter_reply,
 		&args, NULL) == FALSE) {
 		rl_printf("Failed to set discovery filter\n");
@@ -1206,7 +1284,10 @@ static void cmd_set_scan_filter_clear(const char *arg)
 	g_free(filtered_scan_transport);
 	filtered_scan_transport = NULL;
 
-	if (g_dbus_proxy_method_call(default_ctrl, "SetDiscoveryFilter",
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	if (g_dbus_proxy_method_call(default_ctrl->proxy, "SetDiscoveryFilter",
 		clear_discovery_filter_setup, set_discovery_filter_reply,
 		NULL, NULL) == FALSE) {
 		rl_printf("Failed to clear discovery filter\n");
@@ -1224,7 +1305,10 @@ static struct GDBusProxy *find_device(const char *arg)
 		return NULL;
 	}
 
-	proxy = find_proxy_by_address(dev_list, arg);
+	if (check_default_ctrl() == FALSE)
+		return NULL;
+
+	proxy = find_proxy_by_address(default_ctrl->devices, arg);
 	if (!proxy) {
 		rl_printf("Device %s not available\n", arg);
 		return NULL;
@@ -1414,8 +1498,11 @@ static void remove_device(GDBusProxy *proxy)
 	char *path;
 
 	path = g_strdup(g_dbus_proxy_get_path(proxy));
+	
+	if (!default_ctrl)
+		return;
 
-	if (g_dbus_proxy_method_call(default_ctrl, "RemoveDevice",
+	if (g_dbus_proxy_method_call(default_ctrl->proxy, "RemoveDevice",
 						remove_device_setup,
 						remove_device_reply,
 						path, g_free) == FALSE) {
@@ -1439,16 +1526,15 @@ static void cmd_remove(const char *arg)
 	if (strcmp(arg, "*") == 0) {
 		GList *list;
 
-		for (list = g_list_first(dev_list); list; list = g_list_next(list)) {
+		for (list = g_list_first(default_ctrl->devices); list; list = g_list_next(list)) {
 			GDBusProxy *proxy = list->data;
 
 			remove_device(proxy);
 		}
-
 		return;
 	}
 
-	proxy = find_proxy_by_address(dev_list, arg);
+	proxy = find_proxy_by_address(default_ctrl->devices, arg);
 	if (!proxy) {
 		rl_printf("Device %s not available\n", arg);
 		return;
@@ -1484,7 +1570,10 @@ static void cmd_connect(const char *arg)
 		return;
 	}
 
-	proxy = find_proxy_by_address(dev_list, arg);
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	proxy = find_proxy_by_address(default_ctrl->devices, arg);
 	if (!proxy) {
 		rl_printf("Device %s not available\n", arg);
 		return;
@@ -1694,7 +1783,7 @@ static void cmd_register_profile(const char *arg)
 		return;
 	}
 
-	gatt_register_profile(dbus_conn, default_ctrl, &w);
+	gatt_register_profile(dbus_conn, default_ctrl->proxy, &w);
 
 	wordfree(&w);
 }
@@ -1704,7 +1793,7 @@ static void cmd_unregister_profile(const char *arg)
 	if (check_default_ctrl() == FALSE)
 		return;
 
-	gatt_unregister_profile(dbus_conn, default_ctrl);
+	gatt_unregister_profile(dbus_conn, default_ctrl->proxy);
 }
 
 static void cmd_version(const char *arg)
@@ -1750,12 +1839,39 @@ static char *generic_generator(const char *text, int state,
 
 static char *ctrl_generator(const char *text, int state)
 {
-	return generic_generator(text, state, ctrl_list, "Address");
+	static int index = 0;
+	static int len = 0;
+	GList *list;
+
+	if (!state) {
+		index = 0;
+		len = strlen(text);
+	}
+
+	for (list = g_list_nth(ctrl_list, index); list;
+						list = g_list_next(list)) {
+		struct adapter *adapter = list->data;
+		DBusMessageIter iter;
+		const char *str;
+
+		index++;
+
+		if (g_dbus_proxy_get_property(adapter->proxy, "Address", &iter) == FALSE)
+			continue;
+
+		dbus_message_iter_get_basic(&iter, &str);
+
+		if (!strncmp(str, text, len))
+			return strdup(str);
+        }
+
+	return NULL;
 }
 
 static char *dev_generator(const char *text, int state)
 {
-	return generic_generator(text, state, dev_list, "Address");
+	return generic_generator(text, state, 
+			default_ctrl ? default_ctrl->devices : NULL, "Address");
 }
 
 static char *attribute_generator(const char *text, int state)
@@ -2155,7 +2271,6 @@ int main(int argc, char *argv[])
 	g_main_loop_unref(main_loop);
 
 	g_list_free_full(ctrl_list, proxy_leak);
-	g_list_free_full(dev_list, proxy_leak);
 
 	g_free(auto_register_agent);
 
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux