blob: 33c2ba8f891f3d305c879a2fc3bf0409452ac96f [file] [log] [blame]
From 3cfdaba109ba7e2496759ed9d007a0934947a182 Mon Sep 17 00:00:00 2001
From: Alex Deymo <deymo@chromium.org>
Date: Tue, 26 Feb 2013 19:40:52 -0800
Subject: [PATCH] Add GetCachedServices to device API.
This fix implements a new GetCachedServices() function with similar
functionality as DiscoverServices(), except it only retrieves information
from an internal cache.
diff --git a/doc/device-api.txt b/doc/device-api.txt
index e8fc314..bcdfcab 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -47,6 +47,25 @@ Methods dict GetProperties()
org.bluez.Error.Failed
org.bluez.Error.InProgress
+ dict GetCachedServices(string pattern)
+
+ This method is similar to DiscoverServices(pattern)
+ except that the retrieved service records are from
+ an internal cache instead of initiating a remote
+ service discovery. This cache is updated every time
+ DiscoverServices() returns any result. The pattern
+ parameter can be used to specify specific UUIDs.
+ An empty string will return all the records known for
+ this device.
+
+ The return value is a dictionary with the record
+ handles as keys and the service record in XML format
+ as values. The key is uint32 and the value a string
+ for this dictionary. If the cache is empty, an empty
+ dictionary is returned.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
void CancelDiscovery()
This method will cancel any previous DiscoverServices
diff --git a/src/device.c b/src/device.c
index e55f1de..648f93f 100644
--- a/src/device.c
+++ b/src/device.c
@@ -186,6 +186,9 @@ static uint16_t uuid_list[] = {
static GSList *device_drivers = NULL;
+static DBusMessage *build_services_reply(struct browse_req *req, int err,
+ sdp_list_t *recs);
+
static void browse_request_free(struct browse_req *req)
{
if (req->listener_id)
@@ -669,6 +672,62 @@ static void discover_services_req_exit(DBusConnection *conn, void *user_data)
browse_request_cancel(req);
}
+static DBusMessage *device_cached_sdp(struct btd_device *device,
+ DBusConnection *conn, DBusMessage *msg, uuid_t *search)
+{
+ DBusMessage *reply = NULL;
+ struct btd_adapter *adapter = device->adapter;
+ struct browse_req *req;
+ sdp_list_t *records;
+ bdaddr_t src;
+
+ if (!msg)
+ return NULL;
+
+ adapter_get_address(adapter, &src);
+
+ req = g_new0(struct browse_req, 1);
+ req->device = btd_device_ref(device);
+
+ if (conn == NULL)
+ conn = get_dbus_connection();
+ req->conn = dbus_connection_ref(conn);
+ req->msg = dbus_message_ref(msg);
+
+ if (search) {
+ sdp_list_t *tmp_records = NULL;
+ sdp_record_t *rec = NULL;
+ gchar *uuid;
+ tmp_records = read_records(&src, &device->bdaddr);
+
+ uuid = bt_uuid2string(search);
+ if (uuid)
+ rec = find_record_in_list(tmp_records, uuid);
+ if (rec) {
+ records = sdp_list_append(NULL, rec);
+ tmp_records = sdp_list_remove(tmp_records, rec);
+ } else
+ records = NULL;
+
+ if (tmp_records)
+ sdp_list_free(tmp_records,
+ (sdp_free_func_t) sdp_record_free);
+ if (uuid)
+ g_free(uuid);
+ } else {
+ records = read_records(&src, &device->bdaddr);
+ }
+
+ reply = build_services_reply(req, 0, records);
+
+ if (records)
+ sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
+
+ browse_request_free(req);
+
+ return reply;
+}
+
static DBusMessage *discover_services(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -706,6 +765,33 @@ fail:
return btd_error_failed(msg, strerror(-err));
}
+static DBusMessage *get_cached_services(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct btd_device *device = user_data;
+ const char *pattern;
+ DBusMessage *reply = NULL;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID) == FALSE)
+ return btd_error_invalid_args(msg);
+
+ if (strlen(pattern) == 0) {
+ reply = device_cached_sdp(device, conn, msg, NULL);
+ } else {
+ uuid_t uuid;
+
+ if (bt_string2uuid(&uuid, pattern) < 0)
+ return btd_error_invalid_args(msg);
+
+ sdp_uuid128_to_uuid(&uuid);
+
+ reply = device_cached_sdp(device, conn, msg, &uuid);
+ }
+
+ return reply;
+}
+
static const char *browse_request_get_requestor(struct browse_req *req)
{
if (!req->msg)
@@ -729,7 +815,7 @@ static void iter_append_record(DBusMessageIter *dict, uint32_t handle,
dbus_message_iter_close_container(dict, &entry);
}
-static void discover_services_reply(struct browse_req *req, int err,
+static DBusMessage *build_services_reply(struct browse_req *req, int err,
sdp_list_t *recs)
{
DBusMessage *reply;
@@ -746,13 +832,12 @@ static void discover_services_reply(struct browse_req *req, int err,
reply = dbus_message_new_error(req->msg, err_if,
strerror(-err));
- g_dbus_send_message(req->conn, reply);
- return;
+ return reply;
}
reply = dbus_message_new_method_return(req->msg);
if (!reply)
- return;
+ return NULL;
dbus_message_iter_init_append(reply, &iter);
@@ -781,7 +866,17 @@ static void discover_services_reply(struct browse_req *req, int err,
dbus_message_iter_close_container(&iter, &dict);
- g_dbus_send_message(req->conn, reply);
+ return reply;
+}
+
+static void discover_services_reply(struct browse_req *req, int err,
+ sdp_list_t *recs)
+{
+ DBusMessage *reply;
+
+ reply = build_services_reply(req, err, recs);
+ if (reply)
+ g_dbus_send_message(req->conn, reply);
}
static DBusMessage *cancel_discover(DBusConnection *conn,
@@ -888,6 +983,7 @@ static GDBusMethodTable device_methods[] = {
{ "SetProperty", "sv", "", set_property },
{ "DiscoverServices", "s", "a{us}", discover_services,
G_DBUS_METHOD_FLAG_ASYNC},
+ { "GetCachedServices", "s", "a{us}", get_cached_services},
{ "CancelDiscovery", "", "", cancel_discover },
{ "Disconnect", "", "", disconnect,
G_DBUS_METHOD_FLAG_ASYNC},