diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2007-01-14 23:14:14 +0000 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2007-01-14 23:14:14 +0000 |
commit | caaafda2c06ac2f0183b29f8999d814587508e39 (patch) | |
tree | 06913a3502bf7551114b68ed922d36d5447bcd83 | |
parent | 331c95a5f378b5c6483d98fd4eceafa38c6fb57a (diff) |
First change towards reworked service framework
-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); |