diff options
| -rw-r--r-- | hcid/dbus-common.c | 2 | ||||
| -rw-r--r-- | hcid/dbus-manager.c | 189 | ||||
| -rw-r--r-- | hcid/dbus-security.c | 18 | ||||
| -rw-r--r-- | hcid/dbus-service.c | 453 | ||||
| -rw-r--r-- | hcid/dbus-service.h | 29 | ||||
| -rw-r--r-- | hcid/main.c | 3 | 
6 files changed, 224 insertions, 470 deletions
diff --git a/hcid/dbus-common.c b/hcid/dbus-common.c index 278dcf12..5cbcc77c 100644 --- a/hcid/dbus-common.c +++ b/hcid/dbus-common.c @@ -324,7 +324,7 @@ void hcid_dbus_exit(void)  	release_default_agent();  	release_default_auth_agent(); -	release_service_agents(conn); +	release_services(conn);  	/* Unregister all paths in Adapter path hierarchy */  	if (!dbus_connection_list_registered(conn, BASE_PATH, &children)) diff --git a/hcid/dbus-manager.c b/hcid/dbus-manager.c index 301809ee..9418f9ab 100644 --- a/hcid/dbus-manager.c +++ b/hcid/dbus-manager.c @@ -51,7 +51,6 @@  #include "sdp-xml.h"  static int default_adapter_id = -1; -static int autostart = 1;  static uint32_t next_handle = 0x10000; @@ -224,149 +223,6 @@ static DBusHandlerResult list_services(DBusConnection *conn,  	return send_message_and_unref(conn, reply);  } -static void autostart_reply(DBusPendingCall *pcall, void *udata) -{ -	struct service_call *call = udata; -	DBusMessage *agent_reply = dbus_pending_call_steal_reply(pcall); -	DBusError err; - -	dbus_error_init(&err); - -	/* Ignore if the result is an error */ -	if (dbus_set_error_from_message(&err, agent_reply)) { -		error("Service auto start failed: %s(%s)", -			err.message, call->agent->name); -		dbus_error_free(&err); -	} else { -		DBusMessage *message; - -		if (!call->agent) -			goto fail; - -		if (register_agent_records(call->agent->records) < 0) -			goto fail; - -		/* Send a signal to indicate that the service started properly */ -		message = dbus_message_new_signal(dbus_message_get_path(call->msg), -						"org.bluez.Service", -						"Started"); - -		send_message_and_unref(call->conn, message); - -		call->agent->running = SERVICE_RUNNING; -	} -fail: -	dbus_message_unref(agent_reply); -	dbus_pending_call_unref(pcall); -} - -static DBusHandlerResult register_service(DBusConnection *conn, -						DBusMessage *msg, void *data) -{ -	const char *path, *name, *description; -	DBusHandlerResult result; -	DBusMessage *message; -	int err; - -	if (!hcid_dbus_use_experimental()) -		return error_unknown_method(conn, msg); - -	if (!dbus_message_get_args(msg, NULL, -				DBUS_TYPE_STRING, &path, -				DBUS_TYPE_STRING, &name, -				DBUS_TYPE_STRING, &description, -				DBUS_TYPE_INVALID)) -		return error_invalid_arguments(conn, msg); - -	err = register_service_agent(conn, dbus_message_get_sender(msg), -					path, name, description); - -	if (err < 0) { -		if (err == -EADDRNOTAVAIL) -			return error_service_already_exists(conn, msg); - -		return error_failed(conn, msg, -err); -	} - -	/* Report that a new service was registered */ -	message = dbus_message_new_signal(BASE_PATH, MANAGER_INTERFACE, -					"ServiceRegistered"); - -	dbus_message_append_args(message, DBUS_TYPE_STRING, &path, -						DBUS_TYPE_INVALID); - -	send_message_and_unref(conn, message); - -	result = send_message_and_unref(conn, dbus_message_new_method_return(msg)); - -	dbus_connection_flush(conn); - -	/* If autostart feature is enabled: send the Start message to the service agent */ -	if (autostart) { -		DBusPendingCall *pending; -		struct service_agent *agent; -		struct service_call *call; - -		message = dbus_message_new_method_call(NULL, path, -				"org.bluez.ServiceAgent", "Start"); - -		dbus_message_set_destination(message, dbus_message_get_sender(msg)); - -		if (dbus_connection_send_with_reply(conn, message, &pending, START_REPLY_TIMEOUT) == FALSE) { -			dbus_message_unref(message); -			return result; -		} - -		dbus_connection_flush(conn); - -		dbus_connection_get_object_path_data(conn, path, (void *) &agent); - -		call = service_call_new(conn, message, agent); -		dbus_message_unref(message); -		if (!call) -			return result; - -		dbus_pending_call_set_notify(pending, autostart_reply, call, service_call_free); -	} - -	return result; -} - -static DBusHandlerResult unregister_service(DBusConnection *conn, -						DBusMessage *msg, void *data) -{ -	DBusMessage *message; -	const char *path; -	int err; - -	if (!hcid_dbus_use_experimental()) -		return error_unknown_method(conn, msg); - -	if (!dbus_message_get_args(msg, NULL, -				DBUS_TYPE_STRING, &path, -				DBUS_TYPE_INVALID)) -		return error_invalid_arguments(conn, msg); - -	err = unregister_service_agent(conn, -				dbus_message_get_sender(msg), path); -	if (err < 0) { -		/* Only the owner can unregister it */ -		if (err == -EPERM) -			return error_not_authorized(conn, msg); - -		return error_failed(conn, msg, -err); -	} - -	/* Report that the service was unregistered */ -	message = dbus_message_new_signal(BASE_PATH, MANAGER_INTERFACE, -					"ServiceUnregistered"); -	dbus_message_append_args(message, DBUS_TYPE_STRING, &path, -				DBUS_TYPE_INVALID); -	send_message_and_unref(conn, message); - -	return send_message_and_unref(conn, dbus_message_new_method_return(msg)); -} -  static sdp_buf_t *service_record_extract(DBusMessageIter *iter)  {  	sdp_buf_t *sdp_buf; @@ -393,7 +249,7 @@ static sdp_buf_t *service_record_extract(DBusMessageIter *iter)  static DBusHandlerResult add_service_record(DBusConnection *conn,  						DBusMessage *msg, void *data)  { -	struct service_agent *agent; +	struct service *service;  	DBusMessageIter iter, array_iter;  	DBusMessage *reply;  	struct binary_record *rec; @@ -411,12 +267,12 @@ static DBusHandlerResult add_service_record(DBusConnection *conn,  	dbus_message_iter_get_basic(&iter, &path);  	if (!dbus_connection_get_object_path_data(conn, path, -						(void *) &agent)) { +						(void *) &service)) {  		/* If failed the path is invalid! */  		return error_invalid_arguments(conn, msg);  	} -	if (!agent || strcmp(dbus_message_get_sender(msg), agent->id)) +	if (!service || strcmp(dbus_message_get_sender(msg), service->id))  		return error_not_authorized(conn, msg);  	dbus_message_iter_next(&iter); @@ -440,7 +296,7 @@ static DBusHandlerResult add_service_record(DBusConnection *conn,  	/* Assign a new handle */  	rec->ext_handle = next_handle++; -	if (agent->running) { +	if (service->id) {  		uint32_t handle = 0;  		if (register_sdp_record(rec->buf->data,	rec->buf->data_size, &handle) < 0) { @@ -453,7 +309,7 @@ static DBusHandlerResult add_service_record(DBusConnection *conn,  		rec->handle = handle;  	} -	agent->records = g_slist_append(agent->records, rec); +	service->records = g_slist_append(service->records, rec);  	dbus_message_append_args(reply,  				DBUS_TYPE_UINT32, &rec->ext_handle, @@ -471,7 +327,7 @@ fail:  static DBusHandlerResult add_service_record_xml(DBusConnection *conn,  						DBusMessage *msg, void *data)  { -	struct service_agent *agent; +	struct service *service;  	DBusMessage *reply;  	struct binary_record *rec;  	sdp_record_t *sdp_rec; @@ -489,12 +345,12 @@ static DBusHandlerResult add_service_record_xml(DBusConnection *conn,  		return error_invalid_arguments(conn, msg);  	if (!dbus_connection_get_object_path_data(conn, path, -						(void *) &agent)) { +						(void *) &service)) {  		/* If failed the path is invalid! */  		return error_invalid_arguments(conn, msg);  	} -	if (!agent || strcmp(dbus_message_get_sender(msg), agent->id)) +	if (!service || strcmp(dbus_message_get_sender(msg), service->id))  		return error_not_authorized(conn, msg);  	reply = dbus_message_new_method_return(msg); @@ -541,7 +397,7 @@ static DBusHandlerResult add_service_record_xml(DBusConnection *conn,  	/* Assign a new handle */  	rec->ext_handle = next_handle++; -	if (agent->running) { +	if (service->id) {  		uint32_t handle = 0;  		if (register_sdp_record(rec->buf->data,	rec->buf->data_size, &handle) < 0) { @@ -554,7 +410,7 @@ static DBusHandlerResult add_service_record_xml(DBusConnection *conn,  		rec->handle = handle;  	} -	agent->records = g_slist_append(agent->records, rec); +	service->records = g_slist_append(service->records, rec);  	dbus_message_append_args(reply,  				DBUS_TYPE_UINT32, &rec->ext_handle, @@ -572,7 +428,7 @@ fail:  static DBusHandlerResult remove_service_record(DBusConnection *conn,  						DBusMessage *msg, void *data)  { -	struct service_agent *agent; +	struct service *service;  	struct binary_record *rec;  	DBusMessage *reply;  	GSList *l; @@ -589,16 +445,16 @@ static DBusHandlerResult remove_service_record(DBusConnection *conn,  		return error_invalid_arguments(conn, msg);  	if (!dbus_connection_get_object_path_data(conn, path, -						(void *) &agent)) { +						(void *) &service)) {  		/* If failed the path is invalid! */  		return error_invalid_arguments(conn, msg);  	} -	if (!agent || strcmp(dbus_message_get_sender(msg), agent->id)) +	if (!service || strcmp(dbus_message_get_sender(msg), service->id))  		return error_not_authorized(conn, msg); -	l = g_slist_find_custom(agent->records, &handle, (GCompareFunc) binary_record_cmp); +	l = g_slist_find_custom(service->records, &handle, (GCompareFunc) binary_record_cmp);  	if (!l)  		return error_record_does_not_exist(conn, msg); @@ -607,10 +463,10 @@ static DBusHandlerResult remove_service_record(DBusConnection *conn,  		return DBUS_HANDLER_RESULT_NEED_MEMORY;  	rec = l->data; -	agent->records = g_slist_remove(agent->records, rec); +	service->records = g_slist_remove(service->records, rec); -	/* If the service agent is running: remove it from the from sdpd */ -	if (agent->running && rec->handle != 0xffffffff) { +	/* If the service is running: remove it from the from sdpd */ +	if (service->id && rec->handle != 0xffffffff) {  		if (unregister_sdp_record(rec->handle) < 0) {  			error("Service record unregistration failed: %s (%d)",  							strerror(errno), errno); @@ -628,8 +484,6 @@ static struct service_data methods[] = {  	{ "FindAdapter",		find_adapter			},  	{ "ListAdapters",		list_adapters			},  	{ "ListServices",		list_services			}, -	{ "RegisterService",		register_service		}, -	{ "UnregisterService",		unregister_service		},  	{ "AddServiceRecord",		add_service_record		},  	{ "AddServiceRecordFromXML", 	add_service_record_xml		},  	{ "RemoveServiceRecord",	remove_service_record		}, @@ -640,18 +494,11 @@ DBusHandlerResult handle_manager_method(DBusConnection *conn,  						DBusMessage *msg, void *data)  {  	service_handler_func_t handler; -	const char *iface, *path, *name; +	const char *iface, *name;  	iface = dbus_message_get_interface(msg); -	path = dbus_message_get_path(msg);  	name = dbus_message_get_member(msg); -	if ((strcmp(BASE_PATH, path)) && !strcmp(iface, "org.bluez.ServiceAgent")) -		return error_unknown_method(conn, msg); - -	if (strcmp(BASE_PATH, path)) -		return error_no_such_adapter(conn, msg); -  	if (!strcmp(DBUS_INTERFACE_INTROSPECTABLE, iface) &&  					!strcmp("Introspect", name)) {  		return simple_introspect(conn, msg, data); diff --git a/hcid/dbus-security.c b/hcid/dbus-security.c index c49bb32e..26372f7f 100644 --- a/hcid/dbus-security.c +++ b/hcid/dbus-security.c @@ -768,7 +768,7 @@ static DBusHandlerResult authorize_service(DBusConnection *conn,  						DBusMessage *msg, void *data)  {  	const char *service_path, *adapter_path, *address, *action; -	struct service_agent *sagent; +	struct service *service;  	GSList *l;  	if (!hcid_dbus_use_experimental()) @@ -786,17 +786,17 @@ static DBusHandlerResult authorize_service(DBusConnection *conn,  		return error_rejected(conn, msg);  	if (!dbus_connection_get_object_path_data(conn, service_path, -						(void *) &sagent)) +						(void *) &service))  		return error_rejected(conn, msg); -	if (!sagent) +	if (!service)  		return error_service_does_not_exist(conn, msg); -	if (strcmp(dbus_message_get_sender(msg), sagent->id)) +	if (strcmp(dbus_message_get_sender(msg), service->id))  		return error_rejected(conn, msg);  	/* Check it is a trusted device */ -	l = g_slist_find_custom(sagent->trusted_devices, address, (GCompareFunc) strcasecmp); +	l = g_slist_find_custom(service->trusted_devices, address, (GCompareFunc) strcasecmp);  	if (l)  		return send_message_and_unref(conn,  				dbus_message_new_method_return(msg)); @@ -847,7 +847,7 @@ static DBusHandlerResult cancel_authorization_process(DBusConnection *conn,  						DBusMessage *msg, void *data)  {  	const char *service_path, *adapter_path, *address, *action; -	struct service_agent *sagent; +	struct service *service;  	if (!hcid_dbus_use_experimental())  		return error_unknown_method(conn, msg); @@ -864,13 +864,13 @@ static DBusHandlerResult cancel_authorization_process(DBusConnection *conn,  		return error_no_such_adapter(conn, msg);  	if (!dbus_connection_get_object_path_data(conn, service_path, -						(void *) &sagent)) +						(void *) &service))  		return error_not_authorized(conn, msg); -	if (!sagent) +	if (!service)  		return error_service_does_not_exist(conn, msg); -	if (strcmp(dbus_message_get_sender(msg), sagent->id)) +	if (strcmp(dbus_message_get_sender(msg), service->id))  		return error_not_authorized(conn, msg);  	if (!default_auth_agent) diff --git a/hcid/dbus-service.c b/hcid/dbus-service.c index 880941bb..40ab706a 100644 --- a/hcid/dbus-service.c +++ b/hcid/dbus-service.c @@ -29,6 +29,8 @@  #include <errno.h>  #include <unistd.h>  #include <stdlib.h> +#include <dirent.h> +#include <sys/types.h>  #include <dbus/dbus.h> @@ -40,6 +42,9 @@  #include "dbus-service.h"  #include "dbus-hci.h" +#define SERVICE_SUFFIX ".service" +#define SERVICE_GROUP "Bluetooth Service" +  static GSList *services = NULL;  struct binary_record *binary_record_new() @@ -77,7 +82,7 @@ int binary_record_cmp(struct binary_record *rec, uint32_t *handle)  struct service_call *service_call_new(DBusConnection *conn, DBusMessage *msg, -					struct service_agent *agent) +					struct service *service)  {  	struct service_call *call;  	call = malloc(sizeof(struct service_call)); @@ -86,7 +91,7 @@ struct service_call *service_call_new(DBusConnection *conn, DBusMessage *msg,  	memset(call, 0, sizeof(struct service_call));  	call->conn = dbus_connection_ref(conn);  	call->msg = dbus_message_ref(msg); -	call->agent = agent; +	call->service = service;  	return call;  } @@ -108,7 +113,7 @@ void service_call_free(void *data)  }  #if 0 -static int service_agent_cmp(const struct service_agent *a, const struct service_agent *b) +static int service_cmp(const struct service *a, const struct service *b)  {  	int ret; @@ -140,71 +145,37 @@ static int service_agent_cmp(const struct service_agent *a, const struct service  }  #endif -static void service_agent_free(struct service_agent *agent) +static void service_free(struct service *service)  { -	if (!agent) +	if (!service)  		return; -	if (agent->id) -		free(agent->id); +	if (service->id) +		free(service->id); -	if (agent->name) -		free(agent->name); +	if (service->exec) +		free(service->exec); -	if (agent->description) -		free(agent->description); +	if (service->name) +		free(service->name); -	if (agent->trusted_devices) { -		g_slist_foreach(agent->trusted_devices, (GFunc) free, NULL); -		g_slist_free(agent->trusted_devices); -	} +	if (service->descr) +		free(service->descr); -	if (agent->records) { -		g_slist_foreach(agent->records, (GFunc) binary_record_free, NULL); -		g_slist_free(agent->records); +	if (service->trusted_devices) { +		g_slist_foreach(service->trusted_devices, (GFunc) free, NULL); +		g_slist_free(service->trusted_devices);  	} -	free(agent); -} - -static struct service_agent *service_agent_new(const char *id, const char *name, const char *description) -{ -	struct service_agent *agent = malloc(sizeof(struct service_agent)); - -	if (!agent) -		return NULL; - -	memset(agent, 0, sizeof(struct service_agent)); - -	if (id) {	 -		agent->id = strdup(id); -		if (!agent->id) -			goto mem_fail; +	if (service->records) { +		g_slist_foreach(service->records, (GFunc) binary_record_free, NULL); +		g_slist_free(service->records);  	} -	if (name) { -		agent->name = strdup(name); -		if (!agent->name) -			goto mem_fail; -	} - -	if (description) { -		agent->description = strdup(description); -		if (!agent->description) -			goto mem_fail; -	} - -	/* by default when the service agent registers the service must not be running */ -	agent->running = SERVICE_NOT_RUNNING; - -	return agent; - -mem_fail: -	service_agent_free(agent); -	return NULL; +	free(service);  } -int register_agent_records(GSList *lrecords) +int register_service_records(GSList *lrecords)  {  	while (lrecords) {  		struct binary_record *rec = lrecords->data; @@ -226,7 +197,7 @@ int register_agent_records(GSList *lrecords)  	return 0;  } -static int unregister_agent_records(GSList *lrecords) +static int unregister_service_records(GSList *lrecords)  {  	while (lrecords) {  		struct binary_record *rec = lrecords->data; @@ -247,30 +218,30 @@ static int unregister_agent_records(GSList *lrecords)  	return 0;  } -static void service_agent_exit(const char *name, void *data) +static void service_exit(const char *name, void *data)  {  	DBusConnection *conn = data;  	DBusMessage *message;  	GSList *l, *lremove = NULL; -	struct service_agent *agent; +	struct service *service;  	const char *path;  	debug("Service Agent exited:%s", name); -	/* Remove all service agents assigned to this owner */ +	/* Remove all service services assigned to this owner */  	for (l = services; l; l = l->next) {  		path = l->data; -		if (!dbus_connection_get_object_path_data(conn, path, (void *) &agent)) +		if (!dbus_connection_get_object_path_data(conn, path, (void *) &service))  			continue; -		if (!agent || strcmp(name, agent->id)) +		if (!service || strcmp(name, service->id))  			continue; -		if (agent->records) -			unregister_agent_records(agent->records); +		if (service->records) +			unregister_service_records(service->records); -		service_agent_free(agent); +		service_free(service);  		dbus_connection_unregister_object_path(conn, path); @@ -311,7 +282,7 @@ static void forward_reply(DBusPendingCall *call, void *udata)  static DBusHandlerResult get_connection_name(DBusConnection *conn,  						DBusMessage *msg, void *data)  { -	struct service_agent *agent = data; +	struct service *service = data;  	DBusMessage *reply;  	reply = dbus_message_new_method_return(msg); @@ -319,7 +290,7 @@ static DBusHandlerResult get_connection_name(DBusConnection *conn,  		return DBUS_HANDLER_RESULT_NEED_MEMORY;  	dbus_message_append_args(reply, -			DBUS_TYPE_STRING, &agent->id, +			DBUS_TYPE_STRING, &service->id,  			DBUS_TYPE_INVALID);  	return send_message_and_unref(conn, reply); @@ -329,7 +300,7 @@ static DBusHandlerResult get_name(DBusConnection *conn,  					DBusMessage *msg, void *data)  { -	struct service_agent *agent = data; +	struct service *service = data;  	DBusMessage *reply;  	const char *name = ""; @@ -337,8 +308,8 @@ static DBusHandlerResult get_name(DBusConnection *conn,  	if (!reply)  		return DBUS_HANDLER_RESULT_NEED_MEMORY; -	if (agent->name) -		name = agent->name; +	if (service->name) +		name = service->name;  	dbus_message_append_args(reply,  			DBUS_TYPE_STRING, &name, @@ -350,7 +321,7 @@ static DBusHandlerResult get_name(DBusConnection *conn,  static DBusHandlerResult get_description(DBusConnection *conn,  						DBusMessage *msg, void *data)  { -	struct service_agent *agent = data; +	struct service *service = data;  	DBusMessage *reply;  	const char *description = ""; @@ -358,8 +329,8 @@ static DBusHandlerResult get_description(DBusConnection *conn,  	if (!reply)  		return DBUS_HANDLER_RESULT_NEED_MEMORY; -	if (agent->description) -		description = agent->description; +	if (service->descr) +		description = service->descr;  	dbus_message_append_args(reply,  			DBUS_TYPE_STRING, &description, @@ -368,165 +339,32 @@ static DBusHandlerResult get_description(DBusConnection *conn,  	return send_message_and_unref(conn, reply);  } -static void start_reply(DBusPendingCall *call, void *udata) -{ -	struct service_call *call_data = udata; -	DBusMessage *agent_reply = dbus_pending_call_steal_reply(call); -	DBusMessage *source_reply; -	DBusError err; - -	dbus_error_init(&err); -	if (dbus_set_error_from_message(&err, agent_reply)) { -		call_data->agent->running = SERVICE_NOT_RUNNING; -		dbus_error_free(&err); -		/* Forward the error to the requestor */ -	} else { -		DBusMessage *message; - -		if (register_agent_records(call_data->agent->records) < 0) { -			/* FIXME: define a better error name */ -			source_reply = dbus_message_new_error(call_data->msg, -					ERROR_INTERFACE ".Failed", strerror(errno)); -			goto fail; -		} - -		call_data->agent->running = SERVICE_RUNNING; - -		/* Send a signal to indicate that the service started properly */ -		message = dbus_message_new_signal(dbus_message_get_path(call_data->msg), -							"org.bluez.Service", -							"Started"); - -		send_message_and_unref(call_data->conn, message); -	} - -	/* Copy the service agent reply: error message or any reply content */ -	source_reply = dbus_message_copy(agent_reply); -fail: -	dbus_message_set_destination(source_reply, dbus_message_get_sender(call_data->msg)); -	dbus_message_set_no_reply(source_reply, TRUE); -	dbus_message_set_reply_serial(source_reply, dbus_message_get_serial(call_data->msg)); - -	send_message_and_unref(call_data->conn, source_reply); - -	dbus_message_unref(agent_reply); -	dbus_pending_call_unref(call); -} -  static DBusHandlerResult start(DBusConnection *conn,  				DBusMessage *msg, void *data)  { -	DBusPendingCall *pending; -	struct service_call *call_data; -	struct service_agent *agent  = data; -	DBusMessage *forward; +	struct service *service = data; -	if (agent->running) +	if (service->pid)  		return error_failed(conn, msg, EPERM); -	forward = dbus_message_copy(msg); -	if (!forward) -		return DBUS_HANDLER_RESULT_NEED_MEMORY; - -	dbus_message_set_destination(forward, agent->id); -	dbus_message_set_interface(forward, "org.bluez.ServiceAgent"); -	dbus_message_set_path(forward, dbus_message_get_path(msg)); - -	call_data = service_call_new(conn, msg, agent); -	if (!call_data) { -		dbus_message_unref(forward); -		return DBUS_HANDLER_RESULT_NEED_MEMORY; -	} - -	if (dbus_connection_send_with_reply(conn, forward, &pending, START_REPLY_TIMEOUT) == FALSE) { -		service_call_free(call_data); -		dbus_message_unref(forward); -		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -	} - -	dbus_pending_call_set_notify(pending, start_reply, call_data, service_call_free); -	dbus_message_unref(forward); -  	return DBUS_HANDLER_RESULT_HANDLED;  } -static void stop_reply(DBusPendingCall *call, void *udata) -{ -	struct service_call *call_data = udata; -	DBusMessage *agent_reply = dbus_pending_call_steal_reply(call); -	DBusMessage *source_reply; -	DBusError err; - -	dbus_error_init(&err); -	if (dbus_set_error_from_message(&err, agent_reply)) { -		/* Keep the old running value */ -		dbus_error_free(&err); -	} else { -		DBusMessage *message; -		call_data->agent->running = SERVICE_NOT_RUNNING; - -		/* Send a signal to indicate that the service stopped properly */ -		message = dbus_message_new_signal(dbus_message_get_path(call_data->msg), -							"org.bluez.Service", -							"Stopped"); - -		send_message_and_unref(call_data->conn, message); -		unregister_agent_records(call_data->agent->records); - -	} - -	source_reply = dbus_message_copy(agent_reply); -	dbus_message_set_destination(source_reply, dbus_message_get_sender(call_data->msg)); -	dbus_message_set_no_reply(source_reply, TRUE); -	dbus_message_set_reply_serial(source_reply, dbus_message_get_serial(call_data->msg)); - -	send_message_and_unref(call_data->conn, source_reply); - -	dbus_message_unref(agent_reply); -	dbus_pending_call_unref(call); -} -  static DBusHandlerResult stop(DBusConnection *conn,  				DBusMessage *msg, void *data)  { -	DBusPendingCall *pending; -	struct service_call *call_data; -	struct service_agent *agent  = data; -	DBusMessage *forward; +	struct service *service  = data; -	if (!agent->running) +	if (!service->id)  		return error_failed(conn, msg, EPERM); -	forward = dbus_message_copy(msg); -	if (!forward) -		return DBUS_HANDLER_RESULT_NEED_MEMORY; - -	dbus_message_set_destination(forward, agent->id); -	dbus_message_set_interface(forward, "org.bluez.ServiceAgent"); -	dbus_message_set_path(forward, dbus_message_get_path(msg)); - -	call_data = service_call_new(conn, msg, agent); -	if (!call_data) { -		dbus_message_unref(forward); -		return DBUS_HANDLER_RESULT_NEED_MEMORY; -	} - -	if (dbus_connection_send_with_reply(conn, forward, &pending, START_REPLY_TIMEOUT) == FALSE) { -		service_call_free(call_data); -		dbus_message_unref(forward); -		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -	} - -	dbus_pending_call_set_notify(pending, stop_reply, call_data, service_call_free); -	dbus_message_unref(forward); -  	return DBUS_HANDLER_RESULT_HANDLED;  }  static DBusHandlerResult is_running(DBusConnection *conn,  					DBusMessage *msg, void *data)  { -	struct service_agent *agent = data; +	struct service *service = data;  	DBusMessage *reply;  	dbus_bool_t running; @@ -534,7 +372,7 @@ static DBusHandlerResult is_running(DBusConnection *conn,  	if (!reply)  		return DBUS_HANDLER_RESULT_NEED_MEMORY; -	running = (agent->running == SERVICE_RUNNING ? TRUE : FALSE); +	running = service->id ? TRUE : FALSE;  	dbus_message_append_args(reply,  			DBUS_TYPE_BOOLEAN, &running, @@ -558,7 +396,7 @@ static DBusHandlerResult remove_user(DBusConnection *conn,  static DBusHandlerResult set_trusted(DBusConnection *conn,  					DBusMessage *msg, void *data)  { -	struct service_agent *agent = data; +	struct service *service = data;  	GSList *l;  	DBusMessage *reply;  	const char *address; @@ -571,7 +409,7 @@ static DBusHandlerResult set_trusted(DBusConnection *conn,  	if (check_address(address) < 0)  		return error_invalid_arguments(conn, msg); -	l = g_slist_find_custom(agent->trusted_devices, address, (GCompareFunc) strcasecmp); +	l = g_slist_find_custom(service->trusted_devices, address, (GCompareFunc) strcasecmp);  	if (l)  		return error_trusted_device_already_exists(conn, msg); @@ -579,7 +417,7 @@ static DBusHandlerResult set_trusted(DBusConnection *conn,  	if (!reply)  		return DBUS_HANDLER_RESULT_NEED_MEMORY; -	agent->trusted_devices = g_slist_append(agent->trusted_devices, strdup(address)); +	service->trusted_devices = g_slist_append(service->trusted_devices, strdup(address));  	return send_message_and_unref(conn, reply);  } @@ -587,7 +425,7 @@ static DBusHandlerResult set_trusted(DBusConnection *conn,  static DBusHandlerResult is_trusted(DBusConnection *conn,  					DBusMessage *msg, void *data)  { -	struct service_agent *agent = data; +	struct service *service = data;  	GSList *l;  	DBusMessage *reply;  	const char *address; @@ -598,7 +436,7 @@ static DBusHandlerResult is_trusted(DBusConnection *conn,  			DBUS_TYPE_INVALID))  		return error_invalid_arguments(conn, msg); -	l = g_slist_find_custom(agent->trusted_devices, address, (GCompareFunc) strcasecmp); +	l = g_slist_find_custom(service->trusted_devices, address, (GCompareFunc) strcasecmp);  	trusted = (l? TRUE : FALSE);  	reply = dbus_message_new_method_return(msg); @@ -615,7 +453,7 @@ static DBusHandlerResult is_trusted(DBusConnection *conn,  static DBusHandlerResult remove_trust(DBusConnection *conn,  					DBusMessage *msg, void *data)  { -	struct service_agent *agent = data; +	struct service *service = data;  	GSList *l;  	DBusMessage *reply;  	const char *address; @@ -626,7 +464,7 @@ static DBusHandlerResult remove_trust(DBusConnection *conn,  			DBUS_TYPE_INVALID))  		return error_invalid_arguments(conn, msg); -	l = g_slist_find_custom(agent->trusted_devices, address, (GCompareFunc) strcasecmp); +	l = g_slist_find_custom(service->trusted_devices, address, (GCompareFunc) strcasecmp);  	if (!l)  		return error_trusted_device_does_not_exists(conn, msg); @@ -635,7 +473,7 @@ static DBusHandlerResult remove_trust(DBusConnection *conn,  		return DBUS_HANDLER_RESULT_NEED_MEMORY;  	paddress = l->data; -	agent->trusted_devices = g_slist_remove(agent->trusted_devices, l->data); +	service->trusted_devices = g_slist_remove(service->trusted_devices, l->data);  	free(paddress);  	return send_message_and_unref(conn, reply); @@ -659,7 +497,7 @@ static struct service_data services_methods[] = {  static DBusHandlerResult msg_func_services(DBusConnection *conn,  					DBusMessage *msg, void *data)  { -	struct service_agent *agent = data; +	struct service *service = data;  	service_handler_func_t handler;  	DBusPendingCall *pending;  	DBusMessage *forward; @@ -684,10 +522,10 @@ static DBusHandlerResult msg_func_services(DBusConnection *conn,  		if(!forward)  			return DBUS_HANDLER_RESULT_NEED_MEMORY; -		dbus_message_set_destination(forward, agent->id); +		dbus_message_set_destination(forward, service->id);  		dbus_message_set_path(forward, dbus_message_get_path(msg)); -		call_data = service_call_new(conn, msg, agent); +		call_data = service_call_new(conn, msg, service);  		if (!call_data) {  			dbus_message_unref(forward);  			return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -713,57 +551,50 @@ static const DBusObjectPathVTable services_vtable = {  	.unregister_function	= NULL  }; -int register_service_agent(DBusConnection *conn, const char *sender, -				const char *path, const char *name, const char *description) +int register_service(char *path, struct service *service)  { -	struct service_agent *agent; -	GSList *l; +	char obj_path[PATH_MAX], *slash; +	DBusConnection *conn = get_dbus_connection(); -	debug("Registering service object: %s", path); +	path[strlen(path) - strlen(SERVICE_SUFFIX)] = '\0'; +	slash = strrchr(path, '/'); -	/* Check if the name is already used? */ -	agent = service_agent_new(sender, name, description); -	if (!agent) -		return -ENOMEM; +	snprintf(obj_path, sizeof(obj_path) - 1, "/org/bluez/service-%s", &slash[1]); -	l = g_slist_find_custom(services, path, (GCompareFunc) strcmp); -	if (l) -		return -EADDRNOTAVAIL; +	debug("Registering service object: %s (%s)", service->name, obj_path); -	if (!dbus_connection_register_object_path(conn, path, &services_vtable, agent)) { -		free(agent); +	if (!dbus_connection_register_object_path(conn, obj_path, +						&services_vtable, service))  		return -ENOMEM; -	} -	services = g_slist_append(services, strdup(path)); - -	name_listener_add(conn, sender, (name_cb_t) service_agent_exit, conn); +	services = g_slist_append(services, strdup(obj_path));  	return 0;  } -int unregister_service_agent(DBusConnection *conn, const char *sender, const char *path) +int unregister_service(const char *sender, const char *path)  { -	struct service_agent *agent; +	struct service *service; +	DBusConnection *conn = get_dbus_connection();  	GSList *l;  	debug("Unregistering service object: %s", path); -	if (dbus_connection_get_object_path_data(conn, path, (void *) &agent)) { +	if (dbus_connection_get_object_path_data(conn, path, (void *) &service)) {  		/* No data assigned to this path or it is not the owner */ -		if (!agent || strcmp(sender, agent->id)) +		if (!service || strcmp(sender, service->id))  			return -EPERM; -		if (agent->records) -			unregister_agent_records(agent->records); +		if (service->records) +			unregister_service_records(service->records); -		service_agent_free(agent); +		service_free(service);  	}  	if (!dbus_connection_unregister_object_path(conn, path))  		return -ENOMEM; -	name_listener_remove(conn, sender, (name_cb_t) service_agent_exit, conn); +	name_listener_remove(conn, sender, (name_cb_t) service_exit, conn);  	l = g_slist_find_custom(services, path, (GCompareFunc) strcmp);  	if (l) { @@ -775,39 +606,27 @@ int unregister_service_agent(DBusConnection *conn, const char *sender, const cha  	return 0;  } -void send_release(DBusConnection *conn, const char *id, const char *path) -{ -	DBusMessage *msg; - -	msg = dbus_message_new_method_call(id, path, -				"org.bluez.ServiceAgent", "Release"); -	if (!msg) -		return; - -	dbus_message_set_no_reply(msg, TRUE); -	send_message_and_unref(conn, msg); -} - -void release_service_agents(DBusConnection *conn) +void release_services(DBusConnection *conn)  {  	GSList *l = services; -	struct service_agent *agent; +	struct service *service;  	const char *path; +	debug("release_services"); +  	while (l) {  		path = l->data;  		l = l->next; -		if (dbus_connection_get_object_path_data(conn, path, (void *) &agent)) { -			if (!agent) +		if (dbus_connection_get_object_path_data(conn, path, (void *) &service)) { +			if (!service)  				continue; -			if (agent->records) -				unregister_agent_records(agent->records); +			if (service->records) +				unregister_service_records(service->records); -			send_release(conn, agent->id, path); -			service_agent_free(agent); +			service_free(service);  		}  		dbus_connection_unregister_object_path(conn, path); @@ -820,13 +639,97 @@ void release_service_agents(DBusConnection *conn)  void append_available_services(DBusMessageIter *array_iter)  { -	GSList *l = services; -	const char *path; +	GSList *l; -	while (l) { -		path = l->data; +	for (l = services; l != NULL; l = l->next)  		dbus_message_iter_append_basic(array_iter, -					DBUS_TYPE_STRING, &path); -		l = l->next; +					DBUS_TYPE_STRING, &l->data); +} + +static struct service *create_service(const char *file) +{ +	GKeyFile *keyfile; +	struct service *service; + +	service = malloc(sizeof(struct service)); +	if (!service) { +		error("Unable to allocate new service"); +		return NULL;  	} + +	memset(service, 0, sizeof(struct service)); + +	keyfile = g_key_file_new(); + +	if (!g_key_file_load_from_file(keyfile, file, 0, NULL)) { +		error("Parsing %s failed", file); +		goto failed; +	} + +	service->exec = g_key_file_get_string(keyfile, SERVICE_GROUP, +						"Exec", NULL); +	if (!service->exec) { +		error("%s doesn't contain a Exec attribute", file); +		goto failed; +	} + +	service->name = g_key_file_get_string(keyfile, SERVICE_GROUP, +						"Name", NULL); +	if (!service->name) { +		error("%s doesn't contain a Name attribute", file); +		goto failed; +	} + +	service->descr = g_key_file_get_string(keyfile, SERVICE_GROUP, +						"Description", NULL); + +	g_key_file_free(keyfile); + +	return service; + +failed: +	g_key_file_free(keyfile); +	service_free(service); +	return NULL; +} + +int init_services(const char *path) +{ +	DIR *d; +	struct dirent *e; + +	d = opendir(path); +	if (!d) { +		error("Unable to open service dir %s: %s", strerror(errno)); +		return -1; +	} + +	while ((e = readdir(d)) != NULL) { +		char full_path[PATH_MAX]; +		struct service *service; +		size_t len= strlen(e->d_name); + +		if (len < (strlen(SERVICE_SUFFIX) + 1)) +			continue; + +		/* Skip if the file doesn't end in .service */ +		if (strcmp(&e->d_name[len - strlen(SERVICE_SUFFIX)], SERVICE_SUFFIX)) +			continue; + +		snprintf(full_path, sizeof(full_path) - 1, "%s/%s", path, e->d_name); + +		service = create_service(full_path); +		if (!service) { +			error("Unable to read %s", full_path); +			continue; +		} + +		register_service(full_path, service); +	} + +	closedir(d); + +	return 0;  } + + diff --git a/hcid/dbus-service.h b/hcid/dbus-service.h index a431dae3..add33887 100644 --- a/hcid/dbus-service.h +++ b/hcid/dbus-service.h @@ -25,14 +25,17 @@  #define __BLUEZ_DBUS_SERVICE_H  #define START_REPLY_TIMEOUT	5000 -#define SERVICE_RUNNING		1 -#define SERVICE_NOT_RUNNING	0 -struct service_agent { -	char *id;	/* Connection id */ +struct service { +	/* These two are set when the service is running */ +	pid_t pid; +	char *id;		/* Connection id */ + +	/* Information parsed from the service file */ +	char *exec;		/* Location of executable */  	char *name; -	char *description; -	int running; +	char *descr; +  	GSList *trusted_devices;  	GSList *records; 	/* list of binary records */  }; @@ -40,7 +43,7 @@ struct service_agent {  struct service_call {  	DBusConnection *conn;  	DBusMessage *msg; -	struct service_agent *agent; +	struct service *service;  };  struct binary_record { @@ -53,18 +56,16 @@ struct binary_record *binary_record_new();  void binary_record_free(struct binary_record *rec);  int binary_record_cmp(struct binary_record *rec, uint32_t *handle); -int register_service_agent(DBusConnection *conn, const char *sender, const char *path, -				const char *name, const char *description); -int unregister_service_agent(DBusConnection *conn, const char *sender, -				const char *path); +void release_services(DBusConnection *conn); -void release_service_agents(DBusConnection *conn);  void append_available_services(DBusMessageIter *iter); -int register_agent_records(GSList *lrecords); +int register_service_records(GSList *lrecords);  struct service_call *service_call_new(DBusConnection *conn, DBusMessage *msg, -					struct service_agent *agent); +					struct service *service);  void service_call_free(void *data); +int init_services(const char *path); +  #endif /* __BLUEZ_DBUS_SERVICE_H */ diff --git a/hcid/main.c b/hcid/main.c index 9f29e8f9..c7461c03 100644 --- a/hcid/main.c +++ b/hcid/main.c @@ -47,6 +47,7 @@  #include "hcid.h"  #include "sdpd.h"  #include "dbus-common.h" +#include "dbus-service.h"  #include "dbus-hci.h"  struct hcid_opts hcid; @@ -756,6 +757,8 @@ int main(int argc, char *argv[])  	if (sdp)  		start_sdp_server(0, SDP_SERVER_COMPAT); +	init_services(CONFIGDIR); +  	/* Start event processor */  	g_main_run(event_loop);  | 
