diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2007-01-15 18:38:58 +0000 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2007-01-15 18:38:58 +0000 |
commit | 467f83c3ac4e4afba959e8cfd8aadb0f1614c9fb (patch) | |
tree | 0a783f172e5ba87596094dc857f8c5cb63a1b37f /hcid/dbus-service.c | |
parent | e1a0779f9e09f4620fdbb977f9e0a67caafdc5f3 (diff) |
Preliminary support for catching the unique bus name of an execed service
Diffstat (limited to 'hcid/dbus-service.c')
-rw-r--r-- | hcid/dbus-service.c | 85 |
1 files changed, 79 insertions, 6 deletions
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; |