diff options
Diffstat (limited to 'hcid')
-rw-r--r-- | hcid/dbus-database.c | 30 | ||||
-rw-r--r-- | hcid/dbus-service.c | 87 | ||||
-rw-r--r-- | hcid/dbus-service.h | 6 |
3 files changed, 119 insertions, 4 deletions
diff --git a/hcid/dbus-database.c b/hcid/dbus-database.c index 1e0cee3e..f0b13abb 100644 --- a/hcid/dbus-database.c +++ b/hcid/dbus-database.c @@ -43,6 +43,8 @@ #include "sdp-xml.h" #include "dbus-common.h" #include "dbus-error.h" +#include "dbus-hci.h" +#include "dbus-service.h" #include "dbus-database.h" static int sdp_server_enable = 0; @@ -264,10 +266,38 @@ static DBusHandlerResult remove_service_record(DBusConnection *conn, return send_message_and_unref(conn, reply); } +static DBusHandlerResult register_service(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + const char *ident, *name, *desc; + const char *sender; + + if (!hcid_dbus_use_experimental()) + return error_unknown_method(conn, msg); + + if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &ident, + DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &desc, + DBUS_TYPE_INVALID) == FALSE) + return error_invalid_arguments(conn, msg); + + sender = dbus_message_get_sender(msg); + + if (service_register(sender, ident, name, desc) < 0) + return error_failed(conn, msg, EIO); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return send_message_and_unref(conn, reply); +} + static struct service_data database_services[] = { { "AddServiceRecord", add_service_record }, { "AddServiceRecordFromXML", add_service_record_from_xml }, { "RemoveServiceRecord", remove_service_record }, + { "RegisterService", register_service }, { NULL, NULL } }; diff --git a/hcid/dbus-service.c b/hcid/dbus-service.c index 30456591..a09a056f 100644 --- a/hcid/dbus-service.c +++ b/hcid/dbus-service.c @@ -304,7 +304,6 @@ static void service_died(GPid pid, gint status, gpointer data) } } - static gboolean service_shutdown_timeout(gpointer data) { struct service *service = data; @@ -397,7 +396,7 @@ static DBusHandlerResult start(DBusConnection *conn, { struct service *service = data; - if (service->pid) + if (service->internal || service->pid) return error_failed(conn, msg, EALREADY); if (service_start(service, conn) < 0) @@ -413,7 +412,7 @@ static DBusHandlerResult stop(DBusConnection *conn, { struct service *service = data; - if (!service->bus_name) + if (service->internal || !service->bus_name) return error_failed(conn, msg, EPERM); stop_service(service, FALSE); @@ -434,7 +433,7 @@ static DBusHandlerResult is_running(DBusConnection *conn, if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; - running = service->bus_name ? TRUE : FALSE; + running = (service->internal || service->bus_name) ? TRUE : FALSE; dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &running, @@ -718,6 +717,8 @@ static struct service *create_service(const char *file) return NULL; } + service->internal = FALSE; + keyfile = g_key_file_new(); if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { @@ -881,3 +882,81 @@ int init_services(const char *path) return 0; } + +static struct service *create_internal_service(const char *ident, + const char *name, const char *description) +{ + struct service *service; + + service = g_try_new0(struct service, 1); + if (!service) { + error("OOM while allocating new internal service"); + return NULL; + } + + service->filename = g_strdup("internal.service"); + service->name = g_strdup(name); + service->descr = g_strdup(description); + service->ident = g_strdup(ident); + + service->internal = TRUE; + + return service; +} + +static void internal_service_exit(const char *name, struct service *service) +{ + DBusConnection *conn = get_dbus_connection(); + DBusMessage *signal; + + service_exit(name, service); + + if (!conn) + return; + + if (!dbus_connection_unregister_object_path(conn, service->object_path)) + return; + + signal = dbus_message_new_signal(BASE_PATH, MANAGER_INTERFACE, + "ServiceRemoved"); + if (signal) { + dbus_message_append_args(signal, + DBUS_TYPE_STRING, &service->object_path, + DBUS_TYPE_INVALID); + send_message_and_unref(conn, signal); + } + + services = g_slist_remove(services, service); + service_free(service); +} + +int service_register(const char *bus_name, const char *ident, + const char *name, const char *description) +{ + DBusConnection *conn = get_dbus_connection(); + DBusMessage *msg; + struct service *service; + + if (!conn) + return -1; + + service = create_internal_service(ident, name, description); + if (!service) + return -1; + + service->bus_name = g_strdup(bus_name); + + if (register_service(service) < 0) { + service_free(service); + return -1; + } + + name_listener_add(conn, bus_name, (name_cb_t) internal_service_exit, service); + + msg = dbus_message_new_signal(service->object_path, + SERVICE_INTERFACE, "Started"); + if (msg) + send_message_and_unref(conn, msg); + + return 0; +} diff --git a/hcid/dbus-service.h b/hcid/dbus-service.h index 4d65b38e..33e7e056 100644 --- a/hcid/dbus-service.h +++ b/hcid/dbus-service.h @@ -45,6 +45,9 @@ struct service { char *ident; gboolean autostart; + /* Services without a *.service file */ + gboolean internal; + GSList *trusted_devices; }; @@ -58,4 +61,7 @@ int service_start(struct service *service, DBusConnection *conn); int init_services(const char *path); +int service_register(const char *bus_name, const char *ident, + const char *name, const char *description); + #endif /* __BLUEZ_DBUS_SERVICE_H */ |