summaryrefslogtreecommitdiffstats
path: root/hcid/dbus-service.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2007-01-15 18:38:58 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2007-01-15 18:38:58 +0000
commit467f83c3ac4e4afba959e8cfd8aadb0f1614c9fb (patch)
tree0a783f172e5ba87596094dc857f8c5cb63a1b37f /hcid/dbus-service.c
parente1a0779f9e09f4620fdbb977f9e0a67caafdc5f3 (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.c85
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;