From 3583074d3cf36ab52caa48ff7feea4ccd833ffb9 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 4 Nov 2008 14:31:19 -0300 Subject: [PATCH] obexd: Call AddRecord and FindAdapter asynchronously --- obexd/src/bluetooth.c | 174 ++------------------ obexd/src/bluetooth.h | 1 + obexd/src/dbus.h | 2 +- obexd/src/manager.c | 371 ++++++++++++++++++++++++++++++++++++------ obexd/src/obex.h | 2 + 5 files changed, 340 insertions(+), 210 deletions(-) diff --git a/obexd/src/bluetooth.c b/obexd/src/bluetooth.c index a385087ed..6fdeb76a1 100644 --- a/obexd/src/bluetooth.c +++ b/obexd/src/bluetooth.c @@ -46,158 +46,17 @@ #include "obex.h" #include "dbus.h" -const static gchar *opp_record = " \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -"; - -const static gchar *ftp_record = " \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -"; - -const static gchar *pbap_record = " \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -"; - -static uint32_t register_record(const gchar *name, - guint16 service, guint8 channel) -{ - gchar *record; - gint handle; - - switch (service) { - case OBEX_OPP: - record = g_markup_printf_escaped(opp_record, channel, name); - break; - case OBEX_FTP: - record = g_markup_printf_escaped(ftp_record, channel, name); - break; - case OBEX_PBAP: - record = g_markup_printf_escaped(pbap_record, channel, name); - break; - default: - return 0; - } +static GSList *servers = NULL; - handle = add_record(record); - g_free(record); +void bluetooth_servers_foreach(GFunc func, gpointer user_data) +{ + struct server *server; + GSList *l; - return handle; + for (l = servers; l; l = l->next) { + server = l->data; + func(server, user_data); + } } static gboolean connect_event(GIOChannel *io, GIOCondition cond, gpointer user_data) @@ -247,6 +106,9 @@ static void server_destroyed(gpointer user_data) error("Server destroyed"); + servers = g_slist_remove(servers, server); + + g_free(server->name); g_free(server->folder); g_free(server); } @@ -304,17 +166,13 @@ static gint server_register(guint16 service, const gchar *name, guint8 channel, goto failed; } - handle = register_record(name, service, channel); - if (handle == 0) { - err = EIO; - goto failed; - } - server = g_malloc0(sizeof(struct server)); server->service = service; + server->name = g_strdup(name); server->folder = g_strdup(folder); server->auto_accept = auto_accept; server->capability = g_strdup(capability); + server->channel = channel; server->handle = handle; io = g_io_channel_unix_new(sk); @@ -324,7 +182,9 @@ static gint server_register(guint16 service, const gchar *name, guint8 channel, connect_event, server, server_destroyed); g_io_channel_unref(io); - debug("Registered: %s, record handle: 0x%x, folder: %s", name, handle, folder); + servers = g_slist_append(servers, server); + + register_record(server, NULL); return 0; diff --git a/obexd/src/bluetooth.h b/obexd/src/bluetooth.h index bc50c1951..587f9ff9b 100644 --- a/obexd/src/bluetooth.h +++ b/obexd/src/bluetooth.h @@ -31,3 +31,4 @@ gint bluetooth_init(guint service, const gchar *name, const gchar *folder, guint8 channel, gboolean secure, gboolean auto_accept, const gchar *capability); void bluetooth_exit(void); +void bluetooth_servers_foreach(GFunc func, gpointer user_data); diff --git a/obexd/src/dbus.h b/obexd/src/dbus.h index 5c9935433..cf89972a6 100644 --- a/obexd/src/dbus.h +++ b/obexd/src/dbus.h @@ -39,7 +39,7 @@ void register_transfer(guint32 id, struct obex_session *os); void unregister_transfer(guint32 id); -gint add_record(gchar *record); +void register_record(struct server *server, gpointer user_data); gint request_service_authorization(struct server *server, gint nsk); diff --git a/obexd/src/manager.c b/obexd/src/manager.c index 255ce47b0..19c1cb835 100644 --- a/obexd/src/manager.c +++ b/obexd/src/manager.c @@ -37,10 +37,140 @@ #include +#include "bluetooth.h" #include "obexd.h" #include "obex.h" #include "logging.h" +const static gchar *opp_record = " \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +"; + +const static gchar *ftp_record = " \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +"; + +const static gchar *pbap_record = " \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +"; + + #define TRANSFER_INTERFACE OPENOBEX_SERVICE ".Transfer" #define SESSION_INTERFACE OPENOBEX_SERVICE ".Session" @@ -61,6 +191,16 @@ struct pending_request { gint nsk; }; +struct adapter_any { + char *path; /* Adapter ANY path */ + GSList *servers; /* List of servers to register records */ +}; + +static DBusConnection *connection = NULL; +static DBusConnection *system_conn = NULL; +static struct adapter_any *any = NULL; +static guint listener_id = 0; + static void agent_free(struct agent *agent) { g_free(agent->new_folder); @@ -318,8 +458,171 @@ static GDBusMethodTable session_methods[] = { { } }; -static DBusConnection *connection = NULL; -static DBusConnection *system_conn = NULL; +static gchar *create_xml_record(const char *name, + uint16_t service, uint8_t channel) +{ + gchar *xml; + + switch (service) { + case OBEX_OPP: + xml = g_markup_printf_escaped(opp_record, channel, name); + break; + case OBEX_FTP: + xml = g_markup_printf_escaped(ftp_record, channel, name); + break; + case OBEX_PBAP: + xml = g_markup_printf_escaped(pbap_record, channel, name); + break; + default: + xml = NULL; + break; + } + + return xml; +} + +static void add_record_reply(DBusPendingCall *call, gpointer user_data) +{ + struct server *server = user_data; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + uint32_t handle; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("Replied with an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + handle = 0; + } else { + dbus_message_get_args(reply, NULL, + DBUS_TYPE_UINT32, &handle, + DBUS_TYPE_INVALID); + server->handle = handle; + + debug("Registered: %s, handle: 0x%x, folder: %s", + server->name, handle, server->folder); + } + + dbus_message_unref(reply); +} + +static gint add_record(const gchar *path, + const gchar *xml, struct server *server) +{ + DBusMessage *msg; + DBusPendingCall *call; + gint ret = 0; + + msg = dbus_message_new_method_call("org.bluez", path, + "org.bluez.Service", "AddRecord"); + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &xml, + DBUS_TYPE_INVALID); + + if (dbus_connection_send_with_reply(system_conn, + msg, &call, -1) == FALSE) { + ret = -1; + goto failed; + } + + dbus_pending_call_set_notify(call, add_record_reply, server, NULL); + dbus_pending_call_unref(call); + +failed: + dbus_message_unref(msg); + return ret; +} + +void register_record(gpointer data, gpointer user_data) +{ + struct server *server = data; + gchar *xml; + gint ret; + + if (system_conn == NULL) + return; + + if (any->path == NULL) { + /* Adapter ANY is not available yet: Add record later */ + any->servers = g_slist_append(any->servers, server); + return; + } + + xml = create_xml_record(server->name, server->service, server->channel); + ret = add_record(any->path, xml, server); + g_free(xml); +} + +static void find_adapter_reply(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct server *server; + const char *path; + gchar *xml; + GSList *l; + DBusError derr; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("Replied with an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + dbus_message_get_args(reply, NULL, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + any->path = g_strdup(path); + + for (l = any->servers; l; l = l->next) { + server = l->data; + xml = create_xml_record(server->name, + server->service, server->channel); + add_record(path, xml, server); + g_free(xml); + } + + g_slist_free(any->servers); + any->servers = NULL; + +done: + dbus_message_unref(reply); +} + +static gboolean find_adapter_any(gpointer user_data) +{ + DBusMessage *msg; + DBusPendingCall *call; + const char *pattern = "any"; + + msg = dbus_message_new_method_call("org.bluez", "/", + "org.bluez.Manager", "FindAdapter"); + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &pattern, + DBUS_TYPE_INVALID); + + dbus_connection_send_with_reply(system_conn, msg, &call, -1); + dbus_pending_call_set_notify(call, find_adapter_reply, NULL, NULL); + dbus_pending_call_unref(call); + + dbus_message_unref(msg); + + return FALSE; +} + +static void name_acquired(DBusConnection *conn, void *user_data) +{ + find_adapter_any(NULL); + bluetooth_servers_foreach(register_record, NULL); +} + +static void name_released(DBusConnection *conn, void *user_data) +{ + g_free(any->path); + any->path = NULL; +} gboolean manager_init(void) { @@ -327,6 +630,8 @@ gboolean manager_init(void) DBG(""); + any = g_new0(struct adapter_any, 1); + dbus_error_init(&err); connection = g_dbus_setup_bus(DBUS_BUS_SESSION, OPENOBEX_SERVICE, &err); @@ -343,6 +648,11 @@ gboolean manager_init(void) if (system_conn == NULL) return FALSE; + listener_id = g_dbus_add_service_watch(system_conn, "org.bluez", + name_acquired, name_released, NULL, NULL); + + g_idle_add(find_adapter_any, NULL); + return g_dbus_register_interface(connection, OPENOBEX_MANAGER_PATH, OPENOBEX_MANAGER_INTERFACE, manager_methods, manager_signals, NULL, @@ -361,6 +671,13 @@ void manager_cleanup(void) if (agent) agent_free(agent); + g_dbus_remove_watch(system_conn, listener_id); + + if (any) { + g_free(any->path); + g_free(any); + } + if (system_conn) dbus_connection_unref(system_conn); @@ -596,55 +913,6 @@ int request_authorization(gint32 cid, int fd, const gchar *filename, return 0; } -gint add_record(gchar *record) -{ - DBusMessage *msg, *reply; - const gchar *adapter_path; - guint32 handle; - - if (system_conn == NULL) - return 0; - - msg = dbus_message_new_method_call("org.bluez", "/", - "org.bluez.Manager", "DefaultAdapter"); - - reply = dbus_connection_send_with_reply_and_block(system_conn, msg, - -1, NULL); - if (reply == NULL) { - dbus_message_unref(msg); - return 0; - } - - dbus_message_unref(msg); - - dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &adapter_path, - DBUS_TYPE_INVALID); - - dbus_message_unref(reply); - - msg = dbus_message_new_method_call("org.bluez", adapter_path, - "org.bluez.Service", "AddRecord"); - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &record, - DBUS_TYPE_INVALID); - - reply = dbus_connection_send_with_reply_and_block(system_conn, msg, - -1, NULL); - if (reply == NULL) { - dbus_message_unref(msg); - return 0; - } - - dbus_message_unref(msg); - - dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_INVALID); - - dbus_message_unref(reply); - - return handle; -} - static void service_reply(DBusPendingCall *call, gpointer user_data) { struct pending_request *pending = user_data; @@ -784,7 +1052,6 @@ gint request_service_authorization(struct server *server, gint nsk) return 0; } - void register_session(guint32 id, struct obex_session *os) { gchar *path = g_strdup_printf("/session%u", id); diff --git a/obexd/src/obex.h b/obexd/src/obex.h index e1889ec40..0493f452d 100644 --- a/obexd/src/obex.h +++ b/obexd/src/obex.h @@ -47,9 +47,11 @@ struct obex_commands { struct server { guint16 service; gboolean auto_accept; + gchar *name; gchar *folder; gchar *capability; guint32 handle; + uint8_t channel; }; struct obex_session { -- 2.47.3