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 | |
| parent | e1a0779f9e09f4620fdbb977f9e0a67caafdc5f3 (diff) | |
Preliminary support for catching the unique bus name of an execed service
| -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 */ | 
