Hi, On Tue, Mar 24, 2015 at 11:37 AM, Luiz Augusto von Dentz <luiz.dentz@xxxxxxxxx> wrote: > From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> > > This adds initial implementation of RegisterProfile. > --- > src/gatt-database.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 197 insertions(+) > > diff --git a/src/gatt-database.c b/src/gatt-database.c > index e07c70f..e701439 100644 > --- a/src/gatt-database.c > +++ b/src/gatt-database.c > @@ -23,6 +23,7 @@ > > #include <stdint.h> > #include <stdlib.h> > +#include <errno.h> > > #include "lib/bluetooth.h" > #include "lib/sdp.h" > @@ -41,6 +42,7 @@ > #include "device.h" > #include "gatt-database.h" > #include "dbus-common.h" > +#include "profile.h" > > #ifndef ATT_CID > #define ATT_CID 4 > @@ -75,6 +77,7 @@ struct btd_gatt_database { > struct gatt_db_attribute *svc_chngd; > struct gatt_db_attribute *svc_chngd_ccc; > struct queue *services; > + struct queue *profiles; > }; > > struct external_service { > @@ -91,6 +94,14 @@ struct external_service { > struct queue *descs; > }; > > +struct external_profile { > + struct btd_gatt_database *database; > + char *owner; > + char *path; /* Path to GattProfile1 */ > + unsigned int id; > + struct queue *profiles; /* btd_profile list */ > +}; > + > struct external_chrc { > struct external_service *service; > char *path; > @@ -364,6 +375,35 @@ static void service_free(void *data) > free(service); > } > > +static void profile_remove(void *data) > +{ > + struct btd_profile *p = data; > + > + DBG("Removed \"%s\"", p->name); > + > + adapter_foreach(adapter_remove_profile, p); > + > + g_free((void *) p->name); > + g_free((void *) p->remote_uuid); > + > + free(p); > +} > + > +static void profile_free(void *data) > +{ > + struct external_profile *profile = data; > + > + queue_destroy(profile->profiles, profile_remove); > + > + if (profile->id) > + g_dbus_remove_watch(btd_get_dbus_connection(), profile->id); > + > + g_free(profile->owner); > + g_free(profile->path); > + > + free(profile); > +} > + > static void gatt_database_free(void *data) > { > struct btd_gatt_database *database = data; > @@ -390,6 +430,7 @@ static void gatt_database_free(void *data) > > queue_destroy(database->device_states, device_state_free); > queue_destroy(database->services, service_free); > + queue_destroy(database->profiles, profile_free); > queue_destroy(database->ccc_callbacks, ccc_cb_free); > database->device_states = NULL; > database->ccc_callbacks = NULL; > @@ -2133,6 +2174,154 @@ static DBusMessage *manager_unregister_service(DBusConnection *conn, > return dbus_message_new_method_return(msg); > } > > +static void profile_exited(DBusConnection *conn, void *user_data) > +{ > + struct external_profile *profile = user_data; > + > + DBG("\"%s\" exited", profile->owner); > + > + profile->id = 0; > + > + queue_remove(profile->database->profiles, profile); > + > + profile_free(profile); > +} > + > +static int profile_add(struct external_profile *profile, const char *uuid) > +{ > + struct btd_profile *p; > + > + p = new0(struct btd_profile, 1); > + if (!p) > + return -ENOMEM; > + > + /* Assign directly to avoid having extra fields */ > + p->name = (const void *) g_strdup_printf("%s%s/%s", profile->owner, > + profile->path, uuid); > + if (!p->name) > + return -ENOMEM; > + > + p->remote_uuid = (const void *) g_strdup(uuid); > + if (!p->remote_uuid) > + return -ENOMEM; > + > + p->auto_connect = true; > + > + queue_push_tail(profile->profiles, p); > + > + DBG("Added \"%s\"", p->name); > + > + return 0; > +} > + > +static void add_profile(void *data, void *user_data) > +{ > + struct btd_adapter *adapter = user_data; > + > + adapter_add_profile(adapter, data); > +} > + > +static int profile_create(DBusConnection *conn, > + struct btd_gatt_database *database, > + const char *sender, const char *path, > + DBusMessageIter *iter) > +{ > + struct external_profile *profile; > + DBusMessageIter uuids; > + > + if (!path || !g_str_has_prefix(path, "/")) > + return -EINVAL; > + > + profile = new0(struct external_profile, 1); > + if (!profile) > + return -ENOMEM; > + > + profile->owner = g_strdup(sender); > + if (!profile->owner) > + goto fail; > + > + profile->path = g_strdup(path); > + if (!profile->path) > + goto fail; > + > + profile->profiles = queue_new(); > + if (!profile->profiles) > + goto fail; > + > + profile->database = database; > + profile->id = g_dbus_add_disconnect_watch(conn, sender, profile_exited, > + profile, NULL); > + > + dbus_message_iter_recurse(iter, &uuids); > + > + while (dbus_message_iter_get_arg_type(&uuids) == DBUS_TYPE_STRING) { > + const char *uuid; > + > + dbus_message_iter_get_basic(&uuids, &uuid); > + > + if (profile_add(profile, uuid) < 0) > + goto fail; > + > + dbus_message_iter_next(&uuids); > + } > + > + if (queue_isempty(profile->profiles)) > + goto fail; > + > + queue_foreach(profile->profiles, add_profile, database->adapter); > + queue_push_tail(database->profiles, profile); > + > + return 0; > + > +fail: > + profile_free(profile); > + return -EINVAL; > +} > + > +static bool match_profile(const void *a, const void *b) > +{ > + const struct external_profile *profile = a; > + const struct svc_match_data *data = b; > + > + return g_strcmp0(profile->path, data->path) == 0 && > + g_strcmp0(profile->owner, data->sender) == 0; > +} > + > +static DBusMessage *manager_register_profile(DBusConnection *conn, > + DBusMessage *msg, void *user_data) > +{ > + struct btd_gatt_database *database = user_data; > + const char *sender = dbus_message_get_sender(msg); > + DBusMessageIter args; > + const char *path; > + struct svc_match_data match_data; > + > + DBG("sender %s", sender); > + > + if (!dbus_message_iter_init(msg, &args)) > + return btd_error_invalid_args(msg); > + > + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) > + return btd_error_invalid_args(msg); > + > + dbus_message_iter_get_basic(&args, &path); > + > + match_data.path = path; > + match_data.sender = sender; > + > + if (queue_find(database->profiles, match_profile, &match_data)) > + return btd_error_already_exists(msg); > + > + dbus_message_iter_next(&args); > + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY) > + return btd_error_invalid_args(msg); > + > + if (profile_create(conn, database, sender, path, &args) < 0) > + return btd_error_failed(msg, "Failed to register profile"); > + > + return dbus_message_new_method_return(msg); > +} > + > static const GDBusMethodTable manager_methods[] = { > { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterService", > GDBUS_ARGS({ "service", "o" }, { "options", "a{sv}" }), > @@ -2140,6 +2329,10 @@ static const GDBusMethodTable manager_methods[] = { > { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterService", > GDBUS_ARGS({ "service", "o" }), > NULL, manager_unregister_service) }, > + { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterProfile", > + GDBUS_ARGS({ "profile", "o" }, { "UUIDs", "as" }, > + { "options", "a{sv}" }), NULL, > + manager_register_profile) }, > { } > }; > > @@ -2169,6 +2362,10 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter) > if (!database->services) > goto fail; > > + database->profiles = queue_new(); > + if (!database->profiles) > + goto fail; > + > database->ccc_callbacks = queue_new(); > if (!database->ccc_callbacks) > goto fail; > -- > 2.1.0 Applied. -- Luiz Augusto von Dentz -- 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