📄 dbus-service.c
字号:
if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; write_trust(BDADDR_ANY, address, service->ident, TRUE); dbus_connection_emit_signal(conn, service->object_path, SERVICE_INTERFACE, "TrustAdded", DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply);}static DBusHandlerResult list_trusted(DBusConnection *conn, DBusMessage *msg, void *data){ struct service *service = data; DBusMessage *reply; GSList *trusts, *l; char **addrs; int len; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; trusts = list_trusts(BDADDR_ANY, service->ident); addrs = g_new(char *, g_slist_length(trusts)); for (l = trusts, len = 0; l; l = l->next, len++) addrs[len] = l->data; dbus_message_append_args(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &addrs, len, DBUS_TYPE_INVALID); g_free(addrs); g_slist_foreach(trusts, (GFunc) g_free, NULL); g_slist_free(trusts); return send_message_and_unref(conn, reply);}static DBusHandlerResult is_trusted(DBusConnection *conn, DBusMessage *msg, void *data){ struct service *service = data; DBusMessage *reply; const char *address; dbus_bool_t trusted; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID)) return error_invalid_arguments(conn, msg, NULL); if (check_address(address) < 0) return error_invalid_arguments(conn, msg, NULL); trusted = read_trust(BDADDR_ANY, address, service->ident); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &trusted, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply);}static DBusHandlerResult remove_trust(DBusConnection *conn, DBusMessage *msg, void *data){ struct service *service = data; DBusMessage *reply; const char *address; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID)) return error_invalid_arguments(conn, msg, NULL); if (check_address(address) < 0) return error_invalid_arguments(conn, msg, NULL); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; write_trust(BDADDR_ANY, address, service->ident, FALSE); dbus_connection_emit_signal(conn, service->object_path, SERVICE_INTERFACE, "TrustRemoved", DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply);}static DBusMethodVTable service_methods[] = { { "GetInfo", get_info, "", "a{sv}" }, { "GetIdentifier", get_identifier, "", "s" }, { "GetName", get_name, "", "s" }, { "GetDescription", get_description, "", "s" }, { "GetBusName", get_bus_name, "", "s" }, { "Start", start, "", "" }, { "Stop", stop, "", "" }, { "IsRunning", is_running, "", "b" }, { "IsExternal", is_external, "", "b" }, { "SetTrusted", set_trusted, "s", "" }, { "IsTrusted", is_trusted, "s", "b" }, { "RemoveTrust", remove_trust, "s", "" }, { "ListTrusts", list_trusted, "", "as" }, { NULL, NULL, NULL, NULL }};static DBusSignalVTable service_signals[] = { { "Started", "" }, { "Stopped", "" }, { "TrustAdded", "s" }, { "TrustRemoved", "s" }, { NULL, NULL }};static dbus_bool_t service_init(DBusConnection *conn, const char *path){ return dbus_connection_register_interface(conn, path, SERVICE_INTERFACE, service_methods, service_signals, NULL);}static int service_cmp_path(struct service *service, const char *path){ return strcmp(service->object_path, path);}static int service_cmp_ident(struct service *service, const char *ident){ return strcmp(service->ident, ident);}static int register_service(struct service *service){ char obj_path[PATH_MAX], *suffix; DBusConnection *conn = get_dbus_connection(); int i; if (g_slist_find_custom(services, service->ident, (GCompareFunc) service_cmp_ident) || !strcmp(service->ident, GLOBAL_TRUST)) return -EADDRINUSE; if (service->external) { snprintf(obj_path, sizeof(obj_path) - 1, "/org/bluez/external_%s", service->ident); } else { snprintf(obj_path, sizeof(obj_path) - 1, "/org/bluez/service_%s", service->filename); /* Don't include the .service part in the path */ suffix = strstr(obj_path, SERVICE_SUFFIX); *suffix = '\0'; } /* Make the path valid for D-Bus */ for (i = strlen("/org/bluez/"); obj_path[i]; i++) { if (!isalnum(obj_path[i])) obj_path[i] = '_'; } if (g_slist_find_custom(services, obj_path, (GCompareFunc) service_cmp_path)) return -EADDRINUSE; debug("Registering service object: ident=%s, name=%s (%s)", service->ident, service->name, obj_path); if (!dbus_connection_create_object_path(conn, obj_path, service, NULL)) { error("D-Bus failed to register %s object", obj_path); return -1; } if (!service_init(conn, obj_path)) { error("Service init failed"); return -1; } service->object_path = g_strdup(obj_path); services = g_slist_append(services, service); dbus_connection_emit_signal(conn, BASE_PATH, MANAGER_INTERFACE, "ServiceAdded", DBUS_TYPE_STRING, &service->object_path, DBUS_TYPE_INVALID); return 0;}static int unregister_service_for_connection(DBusConnection *connection, struct service *service){ DBusConnection *conn = get_dbus_connection(); debug("Unregistering service object: %s", service->object_path); if (!conn) goto cleanup; if (service->bus_name) name_listener_remove(connection, service->bus_name, (name_cb_t) service_exit, service); dbus_connection_emit_signal(conn, service->object_path, SERVICE_INTERFACE, "Stopped", DBUS_TYPE_INVALID); if (!dbus_connection_destroy_object_path(conn, service->object_path)) { error("D-Bus failed to unregister %s object", service->object_path); return -1; } dbus_connection_emit_signal(conn, BASE_PATH, MANAGER_INTERFACE, "ServiceRemoved", DBUS_TYPE_STRING, &service->object_path, DBUS_TYPE_INVALID);cleanup: if (service->pid) { if (service->startup_timer) { abort_startup(service, conn, ECANCELED); services = g_slist_remove(services, service); removed = g_slist_append(removed, service); } else if (!service->shutdown_timer) stop_service(service, TRUE); } else { services = g_slist_remove(services, service); service_free(service); } return 0;}static int unregister_service(struct service *service){ return unregister_service_for_connection(get_dbus_connection(), service);}void release_services(DBusConnection *conn){ debug("release_services"); g_slist_foreach(services, (GFunc) unregister_service, NULL); g_slist_free(services); services = NULL;}struct service *search_service(DBusConnection *conn, const char *pattern){ GSList *l; for (l = services; l != NULL; l = l->next) { struct service *service = l->data; if (service->ident && !strcmp(service->ident, pattern)) return service; if (service->bus_name && !strcmp(service->bus_name, pattern)) return service; } return NULL;}void append_available_services(DBusMessageIter *array_iter){ GSList *l; for (l = services; l != NULL; l = l->next) { struct service *service = l->data; dbus_message_iter_append_basic(array_iter, DBUS_TYPE_STRING, &service->object_path); }}static struct service *create_service(const char *file){ GKeyFile *keyfile; GError *err = NULL; struct service *service; gboolean autostart; const char *slash; service = g_try_new0(struct service, 1); if (!service) { error("OOM while allocating new service"); return NULL; } service->external = FALSE; keyfile = g_key_file_new(); if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { error("Parsing %s failed: %s", file, err->message); g_error_free(err); goto failed; } service->ident = g_key_file_get_string(keyfile, SERVICE_GROUP, "Identifier", &err); if (err) { debug("%s: %s", file, err->message); g_error_free(err); goto failed; } service->name = g_key_file_get_string(keyfile, SERVICE_GROUP, "Name", &err); if (!service->name) { error("%s: %s", file, err->message); g_error_free(err); goto failed; } slash = strrchr(file, '/'); if (!slash) { error("No slash in service file path!?"); goto failed; } service->filename = g_strdup(slash + 1); service->descr = g_key_file_get_string(keyfile, SERVICE_GROUP, "Description", &err); if (err) { debug("%s: %s", file, err->message); g_error_free(err); err = NULL; } autostart = g_key_file_get_boolean(keyfile, SERVICE_GROUP, "Autostart", &err); if (err) { debug("%s: %s", file, err->message); g_error_free(err); err = NULL; } else service->autostart = autostart; g_key_file_free(keyfile); return service;failed: g_key_file_free(keyfile); service_free(service); return NULL;}static gint service_filename_cmp(struct service *service, const char *filename){ return strcmp(service->filename, filename);}static void service_notify(int action, const char *name, void *user_data){ GSList *l; struct service *service; size_t len; char fullpath[PATH_MAX]; debug("Received notify event %d for %s", action, name); len = strlen(name); if (len < (strlen(SERVICE_SUFFIX) + 1)) return; if (strcmp(name + (len - strlen(SERVICE_SUFFIX)), SERVICE_SUFFIX)) return; switch (action) { case NOTIFY_CREATE: debug("%s was created", name); snprintf(fullpath, sizeof(fullpath) - 1, "%s/%s", CONFIGDIR, name); service = create_service(fullpath); if (!service) { error("Unable to read %s", fullpath); break; } if (register_service(service) < 0) { error("Unable to register service"); service_free(service); break; } if (service->autostart) service_start(service, get_dbus_connection()); break; case NOTIFY_DELETE: debug("%s was deleted", name); l = g_slist_find_custom(services, name, (GCompareFunc) service_filename_cmp); if (l) unregister_service(l->data); break; case NOTIFY_MODIFY: debug("%s was modified", name); break; default: debug("Unknown notify action %d", action); break; }}int init_services(const char *path){ DIR *d; struct dirent *e; d = opendir(path); if (!d) { error("Unable to open service dir %s: %s", path, 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; } if (register_service(service) < 0) { error("Unable to register service"); service_free(service); continue; } if (service->autostart) service_start(service, get_dbus_connection()); } closedir(d); notify_add(path, service_notify, NULL); return 0;}static struct service *create_external_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 external service"); return NULL; } service->filename = NULL; service->name = g_strdup(name); service->descr = g_strdup(description); service->ident = g_strdup(ident); service->external = TRUE; return service;}static void external_service_exit(const char *name, struct service *service){ DBusConnection *conn = get_dbus_connection(); service_exit(name, service); if (!conn) return; if (!dbus_connection_destroy_object_path(conn, service->object_path)) return; dbus_connection_emit_signal(conn, BASE_PATH, MANAGER_INTERFACE, "ServiceRemoved", DBUS_TYPE_STRING, &service->object_path, DBUS_TYPE_INVALID); services = g_slist_remove(services, service); service_free(service);}int service_register(DBusConnection *conn, const char *bus_name, const char *ident, const char *name, const char *description){ struct service *service; if (!conn) return -1; service = create_external_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) external_service_exit, service); dbus_connection_emit_signal(get_dbus_connection(), service->object_path, SERVICE_INTERFACE, "Started", DBUS_TYPE_INVALID); return 0;}int service_unregister(DBusConnection *conn, struct service *service){ return unregister_service_for_connection(conn, service);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -