summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/headset.c77
-rw-r--r--common/dbus.c45
-rw-r--r--common/dbus.h3
-rw-r--r--hcid/dbus-service.c85
-rw-r--r--hcid/dbus-service.h6
5 files changed, 135 insertions, 81 deletions
diff --git a/audio/headset.c b/audio/headset.c
index 144d2668..8499781b 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -1040,28 +1040,6 @@ static DBusHandlerResult stop_message(DBusConnection *conn,
return DBUS_HANDLER_RESULT_HANDLED;
}
-static DBusHandlerResult release_message(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessage *reply;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply) {
- error("Can't create reply message");
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
- }
-
- dbus_connection_send(conn, reply, NULL);
-
- dbus_message_unref(reply);
-
- info("Got Release method. Exiting.");
-
- raise(SIGTERM);
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
static DBusHandlerResult hs_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -1075,8 +1053,6 @@ static DBusHandlerResult hs_message(DBusConnection *conn,
return start_message(conn, msg, data);
if (strcmp(member, "Stop") == 0)
return stop_message(conn, msg, data);
- if (strcmp(member, "Release") == 0)
- return release_message(conn, msg, data);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@@ -1112,38 +1088,8 @@ static const DBusObjectPathVTable hs_table = {
.message_function = hs_message,
};
-static void register_reply(DBusPendingCall *call, void *data)
-{
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusError derr;
-
- dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- error("Registering failed: %s", derr.message);
- dbus_error_free(&derr);
- dbus_message_unref(reply);
- raise(SIGTERM);
- return;
- }
-
- debug("Successfully registered headset service");
-
- dbus_message_unref(reply);
-
- if (config_channel)
- record_id = add_ag_record(config_channel);
-
- if (on_init_bda)
- hs_connect(NULL, NULL, on_init_bda);
-}
-
int headset_dbus_init(char *bda)
{
- DBusMessage *msg;
- DBusPendingCall *pending;
- const char *name = "Headset service";
- const char *description = "A service for headsets";
-
connection = init_dbus(NULL, NULL, NULL);
if (!connection)
return -1;
@@ -1154,26 +1100,11 @@ int headset_dbus_init(char *bda)
return -1;
}
- msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
- "org.bluez.Manager", "RegisterService");
- if (!msg) {
- error("Can't allocate new method call");
- return -1;
- }
-
- dbus_message_append_args(msg, DBUS_TYPE_STRING, &hs_path,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &description,
- DBUS_TYPE_INVALID);
-
- if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {
- error("Sending Register method call failed");
- dbus_message_unref(msg);
- return -1;
- }
+ if (config_channel)
+ record_id = add_ag_record(config_channel);
- dbus_pending_call_set_notify(pending, register_reply, NULL, NULL);
- dbus_message_unref(msg);
+ if (on_init_bda)
+ hs_connect(NULL, NULL, on_init_bda);
return 0;
}
diff --git a/common/dbus.c b/common/dbus.c
index 3b0c1097..070535d7 100644
--- a/common/dbus.c
+++ b/common/dbus.c
@@ -308,6 +308,51 @@ int name_listener_remove(DBusConnection *connection, const char *name,
return 0;
}
+dbus_bool_t dbus_bus_get_unix_process_id(DBusConnection *conn, const char *name,
+ unsigned long *pid)
+{
+ DBusMessage *msg, *reply;
+ dbus_uint32_t pid_arg;
+
+ msg = dbus_message_new_method_call("org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixProcessID");
+ if (!msg) {
+ error("Unable to allocate new message");
+ return FALSE;
+ }
+
+ if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID)) {
+ error("Unable to append arguments to message");
+ dbus_message_unref(msg);
+ return FALSE;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, NULL);
+ if (!reply) {
+ error("Sending GetConnectionUnixProcessID failed");
+ dbus_message_unref(msg);
+ return FALSE;
+ }
+
+ if (!dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &pid_arg,
+ DBUS_TYPE_INVALID)) {
+ error("Getting GetConnectionUnixProcessID args failed");
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return FALSE;
+ }
+
+ *pid = (unsigned long) pid_arg;
+
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+
+ return TRUE;
+}
+
static DBusHandlerResult disconnect_filter(DBusConnection *conn,
DBusMessage *msg, void *data)
{
diff --git a/common/dbus.h b/common/dbus.h
index 393ebcf9..51049391 100644
--- a/common/dbus.h
+++ b/common/dbus.h
@@ -35,6 +35,9 @@ int name_listener_add(DBusConnection *connection, const char *name,
int name_listener_remove(DBusConnection *connection, const char *name,
name_cb_t func, void *user_data);
+dbus_bool_t dbus_bus_get_unix_process_id(DBusConnection *conn, const char *name,
+ unsigned long *pid);
+
DBusHandlerResult simple_introspect(DBusConnection *conn, DBusMessage *msg, void *data);
static inline DBusHandlerResult send_message_and_unref(DBusConnection *conn, DBusMessage *msg)
diff --git a/hcid/dbus-service.c b/hcid/dbus-service.c
index 7bc984a2..e9d851b4 100644
--- a/hcid/dbus-service.c
+++ b/hcid/dbus-service.c
@@ -43,6 +43,8 @@
#include "dbus-service.h"
#include "dbus-hci.h"
+#define SERVICE_INTERFACE "org.bluez.Service"
+
#define SERVICE_SUFFIX ".service"
#define SERVICE_GROUP "Bluetooth Service"
@@ -118,6 +120,9 @@ static void service_free(struct service *service)
if (!service)
return;
+ if (service->object_path)
+ free(service->object_path);
+
if (service->bus_name)
free(service->bus_name);
@@ -324,28 +329,93 @@ static void service_died(GPid pid, gint status, gpointer data)
service->pid = 0;
}
+#define NAME_MATCH "interface=" DBUS_INTERFACE_DBUS ",member=NameOwnerChanged"
+
+static DBusHandlerResult service_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *signal;
+ struct service *service = data;
+ const char *name, *old, *new;
+ unsigned long pid;
+
+ if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old,
+ DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
+ error("Invalid arguments for NameOwnerChanged signal");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (*new == '\0' || *old != '\0' || *new != ':')
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!dbus_bus_get_unix_process_id(conn, new, &pid)) {
+ error("Could not get PID of %s", new);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if ((GPid) pid != service->pid)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ debug("Child PID %d got the unique bus name %s", service->pid, new);
+
+ service->bus_name = strdup(new);
+
+ dbus_bus_remove_match(conn, NAME_MATCH, NULL);
+ dbus_connection_remove_filter(conn, service_filter, service);
+
+ signal = dbus_message_new_signal(service->object_path,
+ SERVICE_INTERFACE, "Started");
+ if (signal)
+ send_message_and_unref(conn, signal);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
static DBusHandlerResult start(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply;
+ GError *err = NULL;
struct service *service = data;
- char *argv[2];
+ char **argv;
+ int argc;
if (service->pid)
return error_failed(conn, msg, EALREADY);
- argv[0] = service->exec;
- argv[1] = NULL;
+ g_shell_parse_argv(service->exec, &argc, &argv, &err);
+
+ if (err != NULL) {
+ error("Unable to parse exec line \"%s\": %s", service->exec, err->message);
+ g_error_free(err);
+ return error_failed(conn, msg, ENOEXEC);
+ }
if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
service_setup, service, &service->pid, NULL)) {
error("Unable to execute %s", service->exec);
+ g_strfreev(argv);
return error_failed(conn, msg, ENOEXEC);
}
+ g_strfreev(argv);
+
service->watch_id = g_child_watch_add(service->pid, service_died,
service);
+ debug("%s executed with PID %d", service->exec, service->pid);
+
+ if (!dbus_connection_add_filter(conn, service_filter, service, NULL)) {
+ error("Unable to add signal filter");
+ kill(service->pid, SIGKILL);
+ }
+
+ dbus_bus_add_match(conn, NAME_MATCH, NULL);
+
reply = dbus_message_new_method_return(msg);
if (reply)
send_message_and_unref(conn, reply);
@@ -522,7 +592,7 @@ static DBusHandlerResult msg_func_services(DBusConnection *conn,
if (!strcmp(DBUS_INTERFACE_INTROSPECTABLE, iface) &&
!strcmp("Introspect", dbus_message_get_member(msg))) {
return simple_introspect(conn, msg, data);
- } else if (strcmp("org.bluez.Service", iface) == 0) {
+ } else if (strcmp(SERVICE_INTERFACE, iface) == 0) {
handler = find_service_handler(services_methods, msg);
if (handler)
@@ -569,14 +639,17 @@ int register_service(char *path, struct service *service)
path[strlen(path) - strlen(SERVICE_SUFFIX)] = '\0';
slash = strrchr(path, '/');
- snprintf(obj_path, sizeof(obj_path) - 1, "/org/bluez/service_%s", &slash[1]);
+ snprintf(obj_path, sizeof(obj_path) - 1, "/org/bluez/service_%s", slash + 1);
- debug("Registering service object: %s (%s)", service->name, obj_path);
+ debug("Registering service object: exec=%s, name=%s (%s)",
+ service->exec, service->name, obj_path);
if (!dbus_connection_register_object_path(conn, obj_path,
&services_vtable, service))
return -ENOMEM;
+ service->object_path = strdup(obj_path);
+
services = g_slist_append(services, strdup(obj_path));
return 0;
diff --git a/hcid/dbus-service.h b/hcid/dbus-service.h
index d3c2f441..043795f3 100644
--- a/hcid/dbus-service.h
+++ b/hcid/dbus-service.h
@@ -27,8 +27,10 @@
#define START_REPLY_TIMEOUT 5000
struct service {
- /* These two are set when the service is running */
- pid_t pid; /* Process id */
+ char *object_path;
+
+ /* These are set when the service is running */
+ GPid pid; /* Process id */
char *bus_name; /* D-Bus unique name */
guint watch_id; /* Id for the child watch */