diff options
-rw-r--r-- | audio/headset.c | 77 | ||||
-rw-r--r-- | common/dbus.c | 45 | ||||
-rw-r--r-- | common/dbus.h | 3 | ||||
-rw-r--r-- | hcid/dbus-service.c | 85 | ||||
-rw-r--r-- | hcid/dbus-service.h | 6 |
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 */ |