X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/7b1b68ce2cfbc735065f1af45811f33a8a6bf6ea..eca082a93f2619cfa10733947a81fa779cb49573:/src/pulsecore/protocol-dbus.c diff --git a/src/pulsecore/protocol-dbus.c b/src/pulsecore/protocol-dbus.c index 95518a13..cf4b9fc5 100644 --- a/src/pulsecore/protocol-dbus.c +++ b/src/pulsecore/protocol-dbus.c @@ -57,18 +57,24 @@ struct connection_entry { DBusConnection *connection; pa_client *client; - pa_bool_t listening_for_all_signals; + bool listening_for_all_signals; /* Contains object paths. If this is empty, then signals from all objects - * are accepted. Only used when listening_for_all_signals == TRUE. */ + * are accepted. Only used when listening_for_all_signals == true. */ pa_idxset *all_signals_objects; - /* Signal name -> idxset. The idxsets contain object paths. If an idxset is - * empty, then that signal is accepted from all objects. Only used when - * listening_for_all_signals == FALSE. */ + /* Signal name -> signal paths entry. The entries contain object paths. If + * a path set is empty, then that signal is accepted from all objects. This + * variable is only used when listening_for_all_signals == false. */ pa_hashmap *listening_signals; }; +/* Only used in connection entries' listening_signals hashmap. */ +struct signal_paths_entry { + char *signal; + pa_idxset *paths; +}; + struct interface_entry { char *name; pa_hashmap *method_handlers; @@ -106,7 +112,7 @@ char *pa_get_dbus_address_from_server_type(pa_server_type_t server_type) { } pa_xfree(runtime_path); - pa_xfree(escaped_path); + dbus_free(escaped_path); return address; } @@ -119,7 +125,7 @@ static pa_dbus_protocol *dbus_protocol_new(pa_core *c) { p = pa_xnew(pa_dbus_protocol, 1); PA_REFCNT_INIT(p); - p->core = pa_core_ref(c); + p->core = c; p->objects = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); p->connections = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); p->extensions = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); @@ -163,17 +169,15 @@ void pa_dbus_protocol_unref(pa_dbus_protocol *p) { pa_assert(pa_hashmap_isempty(p->connections)); pa_assert(pa_idxset_isempty(p->extensions)); - pa_hashmap_free(p->objects, NULL, NULL); - pa_hashmap_free(p->connections, NULL, NULL); - pa_idxset_free(p->extensions, NULL, NULL); + pa_hashmap_free(p->objects); + pa_hashmap_free(p->connections); + pa_idxset_free(p->extensions, NULL); for (i = 0; i < PA_DBUS_PROTOCOL_HOOK_MAX; ++i) pa_hook_done(&p->hooks[i]); pa_assert_se(pa_shared_remove(p->core, "dbus-protocol") >= 0); - pa_core_unref(p->core); - pa_xfree(p); } @@ -287,7 +291,7 @@ enum find_result_t { * mode doesn't match the call. */ PROPERTY_ACCESS_DENIED, - /* The new value signature of a .Set call didn't match the expexted + /* The new value signature of a .Set call didn't match the expected * signature. */ INVALID_PROPERTY_SIG, @@ -356,7 +360,7 @@ static enum find_result_t find_handler_by_method(struct call_info *call_info) { PA_HASHMAP_FOREACH(call_info->iface_entry, call_info->obj_entry->interfaces, state) { if ((call_info->method_handler = pa_hashmap_get(call_info->iface_entry->method_handlers, call_info->method))) { - call_info->expected_method_sig = pa_hashmap_get(call_info->iface_entry->method_signatures, call_info->method); + pa_assert_se(call_info->expected_method_sig = pa_hashmap_get(call_info->iface_entry->method_signatures, call_info->method)); if (pa_streq(call_info->method_sig, call_info->expected_method_sig)) return FOUND_METHOD; @@ -406,7 +410,7 @@ static enum find_result_t find_handler_from_properties_call(struct call_info *ca return NO_SUCH_PROPERTY_INTERFACE; else if ((call_info->property_handler = pa_hashmap_get(call_info->iface_entry->property_handlers, call_info->property))) - return FOUND_GET_PROPERTY; + return call_info->property_handler->get_cb ? FOUND_GET_PROPERTY : PROPERTY_ACCESS_DENIED; else return NO_SUCH_PROPERTY; @@ -440,7 +444,7 @@ static enum find_result_t find_handler_from_properties_call(struct call_info *ca call_info->expected_property_sig = call_info->property_handler->type; if (pa_streq(call_info->property_sig, call_info->expected_property_sig)) - return FOUND_SET_PROPERTY; + return call_info->property_handler->set_cb ? FOUND_SET_PROPERTY : PROPERTY_ACCESS_DENIED; else return INVALID_PROPERTY_SIG; @@ -464,10 +468,15 @@ static enum find_result_t find_handler(struct call_info *call_info) { else if (!(call_info->iface_entry = pa_hashmap_get(call_info->obj_entry->interfaces, call_info->interface))) return NO_SUCH_INTERFACE; - else if ((call_info->method_handler = pa_hashmap_get(call_info->iface_entry->method_handlers, call_info->method))) + else if ((call_info->method_handler = pa_hashmap_get(call_info->iface_entry->method_handlers, call_info->method))) { + pa_assert_se(call_info->expected_method_sig = pa_hashmap_get(call_info->iface_entry->method_signatures, call_info->method)); + + if (!pa_streq(call_info->method_sig, call_info->expected_method_sig)) + return INVALID_METHOD_SIG; + return FOUND_METHOD; - else + } else return NO_SUCH_METHOD; } else { /* The method call doesn't contain an interface. */ @@ -574,6 +583,7 @@ static DBusHandlerResult handle_message_cb(DBusConnection *connection, DBusMessa pa_dbus_send_error(connection, message, DBUS_ERROR_INVALID_ARGS, "Invalid signature for property %s: '%s'. Expected '%s'.", call_info.property, call_info.property_sig, call_info.expected_property_sig); + break; default: pa_assert_not_reached(); @@ -623,6 +633,23 @@ static pa_dbus_arg_info *copy_args(const pa_dbus_arg_info *src, unsigned n) { return dst; } +static void method_handler_free(pa_dbus_method_handler *h) { + unsigned i; + + pa_assert(h); + + pa_xfree((char *) h->method_name); + + for (i = 0; i < h->n_arguments; ++i) { + pa_xfree((char *) h->arguments[i].name); + pa_xfree((char *) h->arguments[i].type); + pa_xfree((char *) h->arguments[i].direction); + } + + pa_xfree((pa_dbus_arg_info *) h->arguments); + pa_xfree(h); +} + static pa_hashmap *create_method_handlers(const pa_dbus_interface_info *info) { pa_hashmap *handlers; unsigned i; @@ -630,7 +657,7 @@ static pa_hashmap *create_method_handlers(const pa_dbus_interface_info *info) { pa_assert(info); pa_assert(info->method_handlers || info->n_method_handlers == 0); - handlers = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + handlers = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) method_handler_free); for (i = 0; i < info->n_method_handlers; ++i) { pa_dbus_method_handler *h = pa_xnew(pa_dbus_method_handler, 1); @@ -639,7 +666,7 @@ static pa_hashmap *create_method_handlers(const pa_dbus_interface_info *info) { h->n_arguments = info->method_handlers[i].n_arguments; h->receive_cb = info->method_handlers[i].receive_cb; - pa_hashmap_put(handlers, h->method_name, h); + pa_hashmap_put(handlers, (char *) h->method_name, h); } return handlers; @@ -654,7 +681,7 @@ static pa_hashmap *extract_method_signatures(pa_hashmap *method_handlers) { pa_assert(method_handlers); - signatures = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + signatures = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree); PA_HASHMAP_FOREACH(handler, method_handlers, state) { sig_buf = pa_strbuf_new(); @@ -664,12 +691,21 @@ static pa_hashmap *extract_method_signatures(pa_hashmap *method_handlers) { pa_strbuf_puts(sig_buf, handler->arguments[i].type); } - pa_hashmap_put(signatures, handler->method_name, pa_strbuf_tostring_free(sig_buf)); + pa_hashmap_put(signatures, (char *) handler->method_name, pa_strbuf_tostring_free(sig_buf)); } return signatures; } +static void property_handler_free(pa_dbus_property_handler *h) { + pa_assert(h); + + pa_xfree((char *) h->property_name); + pa_xfree((char *) h->type); + + pa_xfree(h); +} + static pa_hashmap *create_property_handlers(const pa_dbus_interface_info *info) { pa_hashmap *handlers; unsigned i = 0; @@ -677,7 +713,7 @@ static pa_hashmap *create_property_handlers(const pa_dbus_interface_info *info) pa_assert(info); pa_assert(info->property_handlers || info->n_property_handlers == 0); - handlers = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + handlers = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) property_handler_free); for (i = 0; i < info->n_property_handlers; ++i) { pa_dbus_property_handler *h = pa_xnew(pa_dbus_property_handler, 1); @@ -686,7 +722,7 @@ static pa_hashmap *create_property_handlers(const pa_dbus_interface_info *info) h->get_cb = info->property_handlers[i].get_cb; h->set_cb = info->property_handlers[i].set_cb; - pa_hashmap_put(handlers, h->property_name, h); + pa_hashmap_put(handlers, (char *) h->property_name, h); } return handlers; @@ -720,7 +756,7 @@ int pa_dbus_protocol_add_interface(pa_dbus_protocol *p, void *userdata) { struct object_entry *obj_entry; struct interface_entry *iface_entry; - pa_bool_t obj_entry_created = FALSE; + bool obj_entry_created = false; pa_assert(p); pa_assert(path); @@ -737,8 +773,8 @@ int pa_dbus_protocol_add_interface(pa_dbus_protocol *p, obj_entry->interfaces = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); obj_entry->introspection = NULL; - pa_hashmap_put(p->objects, path, obj_entry); - obj_entry_created = TRUE; + pa_hashmap_put(p->objects, obj_entry->path, obj_entry); + obj_entry_created = true; } if (pa_hashmap_get(obj_entry->interfaces, info->name) != NULL) @@ -765,11 +801,6 @@ int pa_dbus_protocol_add_interface(pa_dbus_protocol *p, return 0; fail: - if (obj_entry_created) { - pa_hashmap_remove(p->objects, path); - pa_xfree(obj_entry); - } - return -1; } @@ -784,40 +815,6 @@ static void unregister_object(pa_dbus_protocol *p, struct object_entry *obj_entr pa_assert_se(dbus_connection_unregister_object_path(conn_entry->connection, obj_entry->path)); } -static void method_handler_free_cb(void *p, void *userdata) { - pa_dbus_method_handler *h = p; - unsigned i; - - pa_assert(h); - - pa_xfree((char *) h->method_name); - - for (i = 0; i < h->n_arguments; ++i) { - pa_xfree((char *) h->arguments[i].name); - pa_xfree((char *) h->arguments[i].type); - pa_xfree((char *) h->arguments[i].direction); - } - - pa_xfree((pa_dbus_arg_info *) h->arguments); -} - -static void method_signature_free_cb(void *p, void *userdata) { - pa_assert(p); - - pa_xfree(p); -} - -static void property_handler_free_cb(void *p, void *userdata) { - pa_dbus_property_handler *h = p; - - pa_assert(h); - - pa_xfree((char *) h->property_name); - pa_xfree((char *) h->type); - - pa_xfree(h); -} - int pa_dbus_protocol_remove_interface(pa_dbus_protocol *p, const char* path, const char* interface) { struct object_entry *obj_entry; struct interface_entry *iface_entry; @@ -838,9 +835,9 @@ int pa_dbus_protocol_remove_interface(pa_dbus_protocol *p, const char* path, con pa_log_debug("Interface %s removed from object %s", iface_entry->name, obj_entry->path); pa_xfree(iface_entry->name); - pa_hashmap_free(iface_entry->method_handlers, method_handler_free_cb, NULL); - pa_hashmap_free(iface_entry->method_signatures, method_signature_free_cb, NULL); - pa_hashmap_free(iface_entry->property_handlers, property_handler_free_cb, NULL); + pa_hashmap_free(iface_entry->method_signatures); + pa_hashmap_free(iface_entry->method_handlers); + pa_hashmap_free(iface_entry->property_handlers); for (i = 0; i < iface_entry->n_signals; ++i) { unsigned j; @@ -864,7 +861,7 @@ int pa_dbus_protocol_remove_interface(pa_dbus_protocol *p, const char* path, con pa_hashmap_remove(p->objects, path); pa_xfree(obj_entry->path); - pa_hashmap_free(obj_entry->interfaces, NULL, NULL); + pa_hashmap_free(obj_entry->interfaces); pa_xfree(obj_entry->introspection); pa_xfree(obj_entry); } @@ -883,6 +880,14 @@ static void register_all_objects(pa_dbus_protocol *p, DBusConnection *conn) { pa_assert_se(dbus_connection_register_object_path(conn, obj_entry->path, &vtable, p)); } +static void signal_paths_entry_free(struct signal_paths_entry *e) { + pa_assert(e); + + pa_xfree(e->signal); + pa_idxset_free(e->paths, pa_xfree); + pa_xfree(e); +} + int pa_dbus_protocol_register_connection(pa_dbus_protocol *p, DBusConnection *conn, pa_client *client) { struct connection_entry *conn_entry; @@ -898,9 +903,10 @@ int pa_dbus_protocol_register_connection(pa_dbus_protocol *p, DBusConnection *co conn_entry = pa_xnew(struct connection_entry, 1); conn_entry->connection = dbus_connection_ref(conn); conn_entry->client = client; - conn_entry->listening_for_all_signals = FALSE; + conn_entry->listening_for_all_signals = false; conn_entry->all_signals_objects = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - conn_entry->listening_signals = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + conn_entry->listening_signals = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, + (pa_free_cb_t) signal_paths_entry_free); pa_hashmap_put(p->connections, conn, conn_entry); @@ -918,22 +924,20 @@ static void unregister_all_objects(pa_dbus_protocol *p, DBusConnection *conn) { pa_assert_se(dbus_connection_unregister_object_path(conn, obj_entry->path)); } -static void free_listened_object_name_cb(void *p, void *userdata) { - pa_assert(p); - - pa_xfree(p); -} +static struct signal_paths_entry *signal_paths_entry_new(const char *signal_name) { + struct signal_paths_entry *e = NULL; -static void free_listening_signals_idxset_cb(void *p, void *userdata) { - pa_idxset *set = p; + pa_assert(signal_name); - pa_assert(set); + e = pa_xnew0(struct signal_paths_entry, 1); + e->signal = pa_xstrdup(signal_name); + e->paths = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - pa_idxset_free(set, free_listened_object_name_cb, NULL); + return e; } int pa_dbus_protocol_unregister_connection(pa_dbus_protocol *p, DBusConnection *conn) { - struct connection_entry *conn_entry; + struct connection_entry *conn_entry = NULL; pa_assert(p); pa_assert(conn); @@ -944,8 +948,8 @@ int pa_dbus_protocol_unregister_connection(pa_dbus_protocol *p, DBusConnection * unregister_all_objects(p, conn); dbus_connection_unref(conn_entry->connection); - pa_idxset_free(conn_entry->all_signals_objects, free_listened_object_name_cb, NULL); - pa_hashmap_free(conn_entry->listening_signals, free_listening_signals_idxset_cb, NULL); + pa_idxset_free(conn_entry->all_signals_objects, pa_xfree); + pa_hashmap_free(conn_entry->listening_signals); pa_xfree(conn_entry); return 0; @@ -969,10 +973,9 @@ void pa_dbus_protocol_add_signal_listener( const char *signal_name, char **objects, unsigned n_objects) { - struct connection_entry *conn_entry; - pa_idxset *object_set; - char *object_path; - unsigned i; + struct connection_entry *conn_entry = NULL; + struct signal_paths_entry *signal_paths_entry = NULL; + unsigned i = 0; pa_assert(p); pa_assert(conn); @@ -982,30 +985,28 @@ void pa_dbus_protocol_add_signal_listener( /* all_signals_objects will either be emptied or replaced with new objects, * so we empty it here unconditionally. If listening_for_all_signals is - * currently FALSE, the idxset is empty already. */ - while ((object_path = pa_idxset_steal_first(conn_entry->all_signals_objects, NULL))) - pa_xfree(object_path); + * currently false, the idxset is empty already so this does nothing. */ + pa_idxset_remove_all(conn_entry->all_signals_objects, pa_xfree); if (signal_name) { - conn_entry->listening_for_all_signals = FALSE; + conn_entry->listening_for_all_signals = false; - /* Replace the old object list with a new one. */ - if ((object_set = pa_hashmap_remove(conn_entry->listening_signals, signal_name))) - pa_idxset_free(object_set, free_listened_object_name_cb, NULL); - object_set = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + /* Replace the old signal paths entry for this signal with a new + * one. */ + pa_hashmap_remove_and_free(conn_entry->listening_signals, signal_name); + signal_paths_entry = signal_paths_entry_new(signal_name); for (i = 0; i < n_objects; ++i) - pa_idxset_put(object_set, pa_xstrdup(objects[i]), NULL); + pa_idxset_put(signal_paths_entry->paths, pa_xstrdup(objects[i]), NULL); - pa_hashmap_put(conn_entry->listening_signals, signal_name, object_set); + pa_hashmap_put(conn_entry->listening_signals, signal_paths_entry->signal, signal_paths_entry); } else { - conn_entry->listening_for_all_signals = TRUE; + conn_entry->listening_for_all_signals = true; /* We're not interested in individual signals anymore, so let's empty * listening_signals. */ - while ((object_set = pa_hashmap_steal_first(conn_entry->listening_signals))) - pa_idxset_free(object_set, free_listened_object_name_cb, NULL); + pa_hashmap_remove_all(conn_entry->listening_signals); for (i = 0; i < n_objects; ++i) pa_idxset_put(conn_entry->all_signals_objects, pa_xstrdup(objects[i]), NULL); @@ -1013,8 +1014,8 @@ void pa_dbus_protocol_add_signal_listener( } void pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection *conn, const char *signal_name) { - struct connection_entry *conn_entry; - pa_idxset *object_set; + struct connection_entry *conn_entry = NULL; + struct signal_paths_entry *signal_paths_entry = NULL; pa_assert(p); pa_assert(conn); @@ -1022,48 +1023,43 @@ void pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection pa_assert_se((conn_entry = pa_hashmap_get(p->connections, conn))); if (signal_name) { - if ((object_set = pa_hashmap_get(conn_entry->listening_signals, signal_name))) - pa_idxset_free(object_set, free_listened_object_name_cb, NULL); + if ((signal_paths_entry = pa_hashmap_remove(conn_entry->listening_signals, signal_name))) + signal_paths_entry_free(signal_paths_entry); } else { - char *object_path; - - conn_entry->listening_for_all_signals = FALSE; - - while ((object_path = pa_idxset_steal_first(conn_entry->all_signals_objects, NULL))) - pa_xfree(object_path); - - while ((object_set = pa_hashmap_steal_first(conn_entry->listening_signals))) - pa_idxset_free(object_set, free_listened_object_name_cb, NULL); + conn_entry->listening_for_all_signals = false; + pa_idxset_remove_all(conn_entry->all_signals_objects, pa_xfree); + pa_hashmap_remove_all(conn_entry->listening_signals); } } -void pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal_name) { +void pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal_msg) { struct connection_entry *conn_entry; + struct signal_paths_entry *signal_paths_entry; void *state = NULL; - pa_idxset *object_set; DBusMessage *signal_copy; char *signal_string; pa_assert(p); - pa_assert(signal_name); - pa_assert(dbus_message_get_type(signal_name) == DBUS_MESSAGE_TYPE_SIGNAL); - pa_assert_se(dbus_message_get_interface(signal_name)); - pa_assert_se(dbus_message_get_member(signal_name)); + pa_assert(signal_msg); + pa_assert(dbus_message_get_type(signal_msg) == DBUS_MESSAGE_TYPE_SIGNAL); + pa_assert(dbus_message_get_path(signal_msg)); + pa_assert(dbus_message_get_interface(signal_msg)); + pa_assert(dbus_message_get_member(signal_msg)); - signal_string = pa_sprintf_malloc("%s.%s", dbus_message_get_interface(signal_name), dbus_message_get_member(signal_name)); + signal_string = pa_sprintf_malloc("%s.%s", dbus_message_get_interface(signal_msg), dbus_message_get_member(signal_msg)); PA_HASHMAP_FOREACH(conn_entry, p->connections, state) { if ((conn_entry->listening_for_all_signals /* Case 1: listening for all signals */ - && (pa_idxset_get_by_data(conn_entry->all_signals_objects, dbus_message_get_path(signal_name), NULL) + && (pa_idxset_get_by_data(conn_entry->all_signals_objects, dbus_message_get_path(signal_msg), NULL) || pa_idxset_isempty(conn_entry->all_signals_objects))) || (!conn_entry->listening_for_all_signals /* Case 2: not listening for all signals */ - && (object_set = pa_hashmap_get(conn_entry->listening_signals, signal_string)) - && (pa_idxset_get_by_data(object_set, dbus_message_get_path(signal_name), NULL) - || pa_idxset_isempty(object_set)))) { + && (signal_paths_entry = pa_hashmap_get(conn_entry->listening_signals, signal_string)) + && (pa_idxset_get_by_data(signal_paths_entry->paths, dbus_message_get_path(signal_msg), NULL) + || pa_idxset_isempty(signal_paths_entry->paths)))) { - pa_assert_se(signal_copy = dbus_message_copy(signal_name)); + pa_assert_se(signal_copy = dbus_message_copy(signal_msg)); pa_assert_se(dbus_connection_send(conn_entry->connection, signal_copy, NULL)); dbus_message_unref(signal_copy); }