153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2009 Tanu Kaskinen 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <dbus/dbus.h> 2553a5a1b3Sopenharmony_ci 2653a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 2753a5a1b3Sopenharmony_ci 2853a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 2953a5a1b3Sopenharmony_ci#include <pulsecore/dbus-util.h> 3053a5a1b3Sopenharmony_ci#include <pulsecore/hashmap.h> 3153a5a1b3Sopenharmony_ci#include <pulsecore/idxset.h> 3253a5a1b3Sopenharmony_ci#include <pulsecore/shared.h> 3353a5a1b3Sopenharmony_ci#include <pulsecore/strbuf.h> 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_ci#include "protocol-dbus.h" 3653a5a1b3Sopenharmony_ci 3753a5a1b3Sopenharmony_cistruct pa_dbus_protocol { 3853a5a1b3Sopenharmony_ci PA_REFCNT_DECLARE; 3953a5a1b3Sopenharmony_ci 4053a5a1b3Sopenharmony_ci pa_core *core; 4153a5a1b3Sopenharmony_ci pa_hashmap *objects; /* Object path -> struct object_entry */ 4253a5a1b3Sopenharmony_ci pa_hashmap *connections; /* DBusConnection -> struct connection_entry */ 4353a5a1b3Sopenharmony_ci pa_idxset *extensions; /* Strings */ 4453a5a1b3Sopenharmony_ci 4553a5a1b3Sopenharmony_ci pa_hook hooks[PA_DBUS_PROTOCOL_HOOK_MAX]; 4653a5a1b3Sopenharmony_ci}; 4753a5a1b3Sopenharmony_ci 4853a5a1b3Sopenharmony_cistruct object_entry { 4953a5a1b3Sopenharmony_ci char *path; 5053a5a1b3Sopenharmony_ci pa_hashmap *interfaces; /* Interface name -> struct interface_entry */ 5153a5a1b3Sopenharmony_ci char *introspection; 5253a5a1b3Sopenharmony_ci}; 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_cistruct connection_entry { 5553a5a1b3Sopenharmony_ci DBusConnection *connection; 5653a5a1b3Sopenharmony_ci pa_client *client; 5753a5a1b3Sopenharmony_ci 5853a5a1b3Sopenharmony_ci bool listening_for_all_signals; 5953a5a1b3Sopenharmony_ci 6053a5a1b3Sopenharmony_ci /* Contains object paths. If this is empty, then signals from all objects 6153a5a1b3Sopenharmony_ci * are accepted. Only used when listening_for_all_signals == true. */ 6253a5a1b3Sopenharmony_ci pa_idxset *all_signals_objects; 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_ci /* Signal name -> signal paths entry. The entries contain object paths. If 6553a5a1b3Sopenharmony_ci * a path set is empty, then that signal is accepted from all objects. This 6653a5a1b3Sopenharmony_ci * variable is only used when listening_for_all_signals == false. */ 6753a5a1b3Sopenharmony_ci pa_hashmap *listening_signals; 6853a5a1b3Sopenharmony_ci}; 6953a5a1b3Sopenharmony_ci 7053a5a1b3Sopenharmony_ci/* Only used in connection entries' listening_signals hashmap. */ 7153a5a1b3Sopenharmony_cistruct signal_paths_entry { 7253a5a1b3Sopenharmony_ci char *signal; 7353a5a1b3Sopenharmony_ci pa_idxset *paths; 7453a5a1b3Sopenharmony_ci}; 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_cistruct interface_entry { 7753a5a1b3Sopenharmony_ci char *name; 7853a5a1b3Sopenharmony_ci pa_hashmap *method_handlers; 7953a5a1b3Sopenharmony_ci pa_hashmap *method_signatures; /* Derived from method_handlers. Contains only "in" arguments. */ 8053a5a1b3Sopenharmony_ci pa_hashmap *property_handlers; 8153a5a1b3Sopenharmony_ci pa_dbus_receive_cb_t get_all_properties_cb; 8253a5a1b3Sopenharmony_ci pa_dbus_signal_info *signals; 8353a5a1b3Sopenharmony_ci unsigned n_signals; 8453a5a1b3Sopenharmony_ci void *userdata; 8553a5a1b3Sopenharmony_ci}; 8653a5a1b3Sopenharmony_ci 8753a5a1b3Sopenharmony_cichar *pa_get_dbus_address_from_server_type(pa_server_type_t server_type) { 8853a5a1b3Sopenharmony_ci char *address = NULL; 8953a5a1b3Sopenharmony_ci char *runtime_path = NULL; 9053a5a1b3Sopenharmony_ci char *escaped_path = NULL; 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_ci switch (server_type) { 9353a5a1b3Sopenharmony_ci case PA_SERVER_TYPE_USER: 9453a5a1b3Sopenharmony_ci pa_assert_se((runtime_path = pa_runtime_path(PA_DBUS_SOCKET_NAME))); 9553a5a1b3Sopenharmony_ci pa_assert_se((escaped_path = dbus_address_escape_value(runtime_path))); 9653a5a1b3Sopenharmony_ci address = pa_sprintf_malloc("unix:path=%s", escaped_path); 9753a5a1b3Sopenharmony_ci break; 9853a5a1b3Sopenharmony_ci 9953a5a1b3Sopenharmony_ci case PA_SERVER_TYPE_SYSTEM: 10053a5a1b3Sopenharmony_ci pa_assert_se((escaped_path = dbus_address_escape_value(PA_DBUS_SYSTEM_SOCKET_PATH))); 10153a5a1b3Sopenharmony_ci address = pa_sprintf_malloc("unix:path=%s", escaped_path); 10253a5a1b3Sopenharmony_ci break; 10353a5a1b3Sopenharmony_ci 10453a5a1b3Sopenharmony_ci case PA_SERVER_TYPE_NONE: 10553a5a1b3Sopenharmony_ci address = pa_xnew0(char, 1); 10653a5a1b3Sopenharmony_ci break; 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci default: 10953a5a1b3Sopenharmony_ci pa_assert_not_reached(); 11053a5a1b3Sopenharmony_ci } 11153a5a1b3Sopenharmony_ci 11253a5a1b3Sopenharmony_ci pa_xfree(runtime_path); 11353a5a1b3Sopenharmony_ci dbus_free(escaped_path); 11453a5a1b3Sopenharmony_ci 11553a5a1b3Sopenharmony_ci return address; 11653a5a1b3Sopenharmony_ci} 11753a5a1b3Sopenharmony_ci 11853a5a1b3Sopenharmony_cistatic pa_dbus_protocol *dbus_protocol_new(pa_core *c) { 11953a5a1b3Sopenharmony_ci pa_dbus_protocol *p; 12053a5a1b3Sopenharmony_ci unsigned i; 12153a5a1b3Sopenharmony_ci 12253a5a1b3Sopenharmony_ci pa_assert(c); 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci p = pa_xnew(pa_dbus_protocol, 1); 12553a5a1b3Sopenharmony_ci PA_REFCNT_INIT(p); 12653a5a1b3Sopenharmony_ci p->core = c; 12753a5a1b3Sopenharmony_ci p->objects = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); 12853a5a1b3Sopenharmony_ci p->connections = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); 12953a5a1b3Sopenharmony_ci p->extensions = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); 13053a5a1b3Sopenharmony_ci 13153a5a1b3Sopenharmony_ci for (i = 0; i < PA_DBUS_PROTOCOL_HOOK_MAX; ++i) 13253a5a1b3Sopenharmony_ci pa_hook_init(&p->hooks[i], p); 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci pa_assert_se(pa_shared_set(c, "dbus-protocol", p) >= 0); 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci return p; 13753a5a1b3Sopenharmony_ci} 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_cipa_dbus_protocol* pa_dbus_protocol_get(pa_core *c) { 14053a5a1b3Sopenharmony_ci pa_dbus_protocol *p; 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci if ((p = pa_shared_get(c, "dbus-protocol"))) 14353a5a1b3Sopenharmony_ci return pa_dbus_protocol_ref(p); 14453a5a1b3Sopenharmony_ci 14553a5a1b3Sopenharmony_ci return dbus_protocol_new(c); 14653a5a1b3Sopenharmony_ci} 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_cipa_dbus_protocol* pa_dbus_protocol_ref(pa_dbus_protocol *p) { 14953a5a1b3Sopenharmony_ci pa_assert(p); 15053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 15153a5a1b3Sopenharmony_ci 15253a5a1b3Sopenharmony_ci PA_REFCNT_INC(p); 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_ci return p; 15553a5a1b3Sopenharmony_ci} 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_civoid pa_dbus_protocol_unref(pa_dbus_protocol *p) { 15853a5a1b3Sopenharmony_ci unsigned i; 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci pa_assert(p); 16153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_ci if (PA_REFCNT_DEC(p) > 0) 16453a5a1b3Sopenharmony_ci return; 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci pa_assert(pa_hashmap_isempty(p->objects)); 16753a5a1b3Sopenharmony_ci pa_assert(pa_hashmap_isempty(p->connections)); 16853a5a1b3Sopenharmony_ci pa_assert(pa_idxset_isempty(p->extensions)); 16953a5a1b3Sopenharmony_ci 17053a5a1b3Sopenharmony_ci pa_hashmap_free(p->objects); 17153a5a1b3Sopenharmony_ci pa_hashmap_free(p->connections); 17253a5a1b3Sopenharmony_ci pa_idxset_free(p->extensions, NULL); 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci for (i = 0; i < PA_DBUS_PROTOCOL_HOOK_MAX; ++i) 17553a5a1b3Sopenharmony_ci pa_hook_done(&p->hooks[i]); 17653a5a1b3Sopenharmony_ci 17753a5a1b3Sopenharmony_ci pa_assert_se(pa_shared_remove(p->core, "dbus-protocol") >= 0); 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci pa_xfree(p); 18053a5a1b3Sopenharmony_ci} 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_cistatic void update_introspection(struct object_entry *oe) { 18353a5a1b3Sopenharmony_ci pa_strbuf *buf; 18453a5a1b3Sopenharmony_ci void *interfaces_state = NULL; 18553a5a1b3Sopenharmony_ci struct interface_entry *iface_entry = NULL; 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci pa_assert(oe); 18853a5a1b3Sopenharmony_ci 18953a5a1b3Sopenharmony_ci buf = pa_strbuf_new(); 19053a5a1b3Sopenharmony_ci pa_strbuf_puts(buf, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE); 19153a5a1b3Sopenharmony_ci pa_strbuf_puts(buf, "<node>\n"); 19253a5a1b3Sopenharmony_ci 19353a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(iface_entry, oe->interfaces, interfaces_state) { 19453a5a1b3Sopenharmony_ci pa_dbus_method_handler *method_handler; 19553a5a1b3Sopenharmony_ci pa_dbus_property_handler *property_handler; 19653a5a1b3Sopenharmony_ci void *handlers_state = NULL; 19753a5a1b3Sopenharmony_ci unsigned i; 19853a5a1b3Sopenharmony_ci unsigned j; 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci pa_strbuf_printf(buf, " <interface name=\"%s\">\n", iface_entry->name); 20153a5a1b3Sopenharmony_ci 20253a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(method_handler, iface_entry->method_handlers, handlers_state) { 20353a5a1b3Sopenharmony_ci pa_strbuf_printf(buf, " <method name=\"%s\">\n", method_handler->method_name); 20453a5a1b3Sopenharmony_ci 20553a5a1b3Sopenharmony_ci for (i = 0; i < method_handler->n_arguments; ++i) 20653a5a1b3Sopenharmony_ci pa_strbuf_printf(buf, " <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n", 20753a5a1b3Sopenharmony_ci method_handler->arguments[i].name, 20853a5a1b3Sopenharmony_ci method_handler->arguments[i].type, 20953a5a1b3Sopenharmony_ci method_handler->arguments[i].direction); 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_ci pa_strbuf_puts(buf, " </method>\n"); 21253a5a1b3Sopenharmony_ci } 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci handlers_state = NULL; 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(property_handler, iface_entry->property_handlers, handlers_state) 21753a5a1b3Sopenharmony_ci pa_strbuf_printf(buf, " <property name=\"%s\" type=\"%s\" access=\"%s\"/>\n", 21853a5a1b3Sopenharmony_ci property_handler->property_name, 21953a5a1b3Sopenharmony_ci property_handler->type, 22053a5a1b3Sopenharmony_ci property_handler->get_cb ? (property_handler->set_cb ? "readwrite" : "read") : "write"); 22153a5a1b3Sopenharmony_ci 22253a5a1b3Sopenharmony_ci for (i = 0; i < iface_entry->n_signals; ++i) { 22353a5a1b3Sopenharmony_ci pa_strbuf_printf(buf, " <signal name=\"%s\">\n", iface_entry->signals[i].name); 22453a5a1b3Sopenharmony_ci 22553a5a1b3Sopenharmony_ci for (j = 0; j < iface_entry->signals[i].n_arguments; ++j) 22653a5a1b3Sopenharmony_ci pa_strbuf_printf(buf, " <arg name=\"%s\" type=\"%s\"/>\n", iface_entry->signals[i].arguments[j].name, 22753a5a1b3Sopenharmony_ci iface_entry->signals[i].arguments[j].type); 22853a5a1b3Sopenharmony_ci 22953a5a1b3Sopenharmony_ci pa_strbuf_puts(buf, " </signal>\n"); 23053a5a1b3Sopenharmony_ci } 23153a5a1b3Sopenharmony_ci 23253a5a1b3Sopenharmony_ci pa_strbuf_puts(buf, " </interface>\n"); 23353a5a1b3Sopenharmony_ci } 23453a5a1b3Sopenharmony_ci 23553a5a1b3Sopenharmony_ci pa_strbuf_puts(buf, " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n" 23653a5a1b3Sopenharmony_ci " <method name=\"Introspect\">\n" 23753a5a1b3Sopenharmony_ci " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" 23853a5a1b3Sopenharmony_ci " </method>\n" 23953a5a1b3Sopenharmony_ci " </interface>\n" 24053a5a1b3Sopenharmony_ci " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n" 24153a5a1b3Sopenharmony_ci " <method name=\"Get\">\n" 24253a5a1b3Sopenharmony_ci " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" 24353a5a1b3Sopenharmony_ci " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" 24453a5a1b3Sopenharmony_ci " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n" 24553a5a1b3Sopenharmony_ci " </method>\n" 24653a5a1b3Sopenharmony_ci " <method name=\"Set\">\n" 24753a5a1b3Sopenharmony_ci " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" 24853a5a1b3Sopenharmony_ci " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" 24953a5a1b3Sopenharmony_ci " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n" 25053a5a1b3Sopenharmony_ci " </method>\n" 25153a5a1b3Sopenharmony_ci " <method name=\"GetAll\">\n" 25253a5a1b3Sopenharmony_ci " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" 25353a5a1b3Sopenharmony_ci " <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n" 25453a5a1b3Sopenharmony_ci " </method>\n" 25553a5a1b3Sopenharmony_ci " </interface>\n"); 25653a5a1b3Sopenharmony_ci 25753a5a1b3Sopenharmony_ci pa_strbuf_puts(buf, "</node>\n"); 25853a5a1b3Sopenharmony_ci 25953a5a1b3Sopenharmony_ci pa_xfree(oe->introspection); 26053a5a1b3Sopenharmony_ci oe->introspection = pa_strbuf_to_string_free(buf); 26153a5a1b3Sopenharmony_ci} 26253a5a1b3Sopenharmony_ci 26353a5a1b3Sopenharmony_ci/* Return value of find_handler() and its subfunctions. */ 26453a5a1b3Sopenharmony_cienum find_result_t { 26553a5a1b3Sopenharmony_ci /* The received message is a valid .Get call. */ 26653a5a1b3Sopenharmony_ci FOUND_GET_PROPERTY, 26753a5a1b3Sopenharmony_ci 26853a5a1b3Sopenharmony_ci /* The received message is a valid .Set call. */ 26953a5a1b3Sopenharmony_ci FOUND_SET_PROPERTY, 27053a5a1b3Sopenharmony_ci 27153a5a1b3Sopenharmony_ci /* The received message is a valid .GetAll call. */ 27253a5a1b3Sopenharmony_ci FOUND_GET_ALL, 27353a5a1b3Sopenharmony_ci 27453a5a1b3Sopenharmony_ci /* The received message is a valid method call. */ 27553a5a1b3Sopenharmony_ci FOUND_METHOD, 27653a5a1b3Sopenharmony_ci 27753a5a1b3Sopenharmony_ci /* The interface of the received message hasn't been registered for the 27853a5a1b3Sopenharmony_ci * destination object. */ 27953a5a1b3Sopenharmony_ci NO_SUCH_INTERFACE, 28053a5a1b3Sopenharmony_ci 28153a5a1b3Sopenharmony_ci /* No property handler was found for the received .Get or .Set call. */ 28253a5a1b3Sopenharmony_ci NO_SUCH_PROPERTY, 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci /* The interface argument of a property call didn't match any registered 28553a5a1b3Sopenharmony_ci * interface. */ 28653a5a1b3Sopenharmony_ci NO_SUCH_PROPERTY_INTERFACE, 28753a5a1b3Sopenharmony_ci 28853a5a1b3Sopenharmony_ci /* The received message called .Get or .Set for a property whose access 28953a5a1b3Sopenharmony_ci * mode doesn't match the call. */ 29053a5a1b3Sopenharmony_ci PROPERTY_ACCESS_DENIED, 29153a5a1b3Sopenharmony_ci 29253a5a1b3Sopenharmony_ci /* The new value signature of a .Set call didn't match the expected 29353a5a1b3Sopenharmony_ci * signature. */ 29453a5a1b3Sopenharmony_ci INVALID_PROPERTY_SIG, 29553a5a1b3Sopenharmony_ci 29653a5a1b3Sopenharmony_ci /* No method handler was found for the received message. */ 29753a5a1b3Sopenharmony_ci NO_SUCH_METHOD, 29853a5a1b3Sopenharmony_ci 29953a5a1b3Sopenharmony_ci /* The signature of the received message didn't match the expected 30053a5a1b3Sopenharmony_ci * signature. Despite the name, this can also be returned for a property 30153a5a1b3Sopenharmony_ci * call if its message signature is invalid. */ 30253a5a1b3Sopenharmony_ci INVALID_METHOD_SIG 30353a5a1b3Sopenharmony_ci}; 30453a5a1b3Sopenharmony_ci 30553a5a1b3Sopenharmony_ci/* Data for resolving the correct reaction to a received message. */ 30653a5a1b3Sopenharmony_cistruct call_info { 30753a5a1b3Sopenharmony_ci DBusMessage *message; /* The received message. */ 30853a5a1b3Sopenharmony_ci struct object_entry *obj_entry; 30953a5a1b3Sopenharmony_ci const char *interface; /* Destination interface name (extracted from the message). */ 31053a5a1b3Sopenharmony_ci struct interface_entry *iface_entry; 31153a5a1b3Sopenharmony_ci 31253a5a1b3Sopenharmony_ci const char *property; /* Property name (extracted from the message). */ 31353a5a1b3Sopenharmony_ci const char *property_interface; /* The interface argument of a property call is stored here. */ 31453a5a1b3Sopenharmony_ci pa_dbus_property_handler *property_handler; 31553a5a1b3Sopenharmony_ci const char *expected_property_sig; /* Property signature from the introspection data. */ 31653a5a1b3Sopenharmony_ci char *property_sig; /* The signature of the new value in the received .Set message. */ 31753a5a1b3Sopenharmony_ci DBusMessageIter variant_iter; /* Iterator pointing to the beginning of the new value variant of a .Set call. */ 31853a5a1b3Sopenharmony_ci 31953a5a1b3Sopenharmony_ci const char *method; /* Method name (extracted from the message). */ 32053a5a1b3Sopenharmony_ci pa_dbus_method_handler *method_handler; 32153a5a1b3Sopenharmony_ci const char *expected_method_sig; /* Method signature from the introspection data. */ 32253a5a1b3Sopenharmony_ci const char *method_sig; /* The signature of the received message. */ 32353a5a1b3Sopenharmony_ci}; 32453a5a1b3Sopenharmony_ci 32553a5a1b3Sopenharmony_ci/* Called when call_info->property has been set and the property interface has 32653a5a1b3Sopenharmony_ci * not been given. In case of a Set call, call_info->property_sig is also set, 32753a5a1b3Sopenharmony_ci * which is checked against the expected value in this function. */ 32853a5a1b3Sopenharmony_cistatic enum find_result_t find_handler_by_property(struct call_info *call_info) { 32953a5a1b3Sopenharmony_ci void *state = NULL; 33053a5a1b3Sopenharmony_ci 33153a5a1b3Sopenharmony_ci pa_assert(call_info); 33253a5a1b3Sopenharmony_ci 33353a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(call_info->iface_entry, call_info->obj_entry->interfaces, state) { 33453a5a1b3Sopenharmony_ci if ((call_info->property_handler = pa_hashmap_get(call_info->iface_entry->property_handlers, call_info->property))) { 33553a5a1b3Sopenharmony_ci if (pa_streq(call_info->method, "Get")) 33653a5a1b3Sopenharmony_ci return call_info->property_handler->get_cb ? FOUND_GET_PROPERTY : PROPERTY_ACCESS_DENIED; 33753a5a1b3Sopenharmony_ci 33853a5a1b3Sopenharmony_ci else if (pa_streq(call_info->method, "Set")) { 33953a5a1b3Sopenharmony_ci call_info->expected_property_sig = call_info->property_handler->type; 34053a5a1b3Sopenharmony_ci 34153a5a1b3Sopenharmony_ci if (pa_streq(call_info->property_sig, call_info->expected_property_sig)) 34253a5a1b3Sopenharmony_ci return call_info->property_handler->set_cb ? FOUND_SET_PROPERTY : PROPERTY_ACCESS_DENIED; 34353a5a1b3Sopenharmony_ci else 34453a5a1b3Sopenharmony_ci return INVALID_PROPERTY_SIG; 34553a5a1b3Sopenharmony_ci 34653a5a1b3Sopenharmony_ci } else 34753a5a1b3Sopenharmony_ci pa_assert_not_reached(); 34853a5a1b3Sopenharmony_ci } 34953a5a1b3Sopenharmony_ci } 35053a5a1b3Sopenharmony_ci 35153a5a1b3Sopenharmony_ci return NO_SUCH_PROPERTY; 35253a5a1b3Sopenharmony_ci} 35353a5a1b3Sopenharmony_ci 35453a5a1b3Sopenharmony_cistatic enum find_result_t find_handler_by_method(struct call_info *call_info) { 35553a5a1b3Sopenharmony_ci void *state = NULL; 35653a5a1b3Sopenharmony_ci 35753a5a1b3Sopenharmony_ci pa_assert(call_info); 35853a5a1b3Sopenharmony_ci 35953a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(call_info->iface_entry, call_info->obj_entry->interfaces, state) { 36053a5a1b3Sopenharmony_ci if ((call_info->method_handler = pa_hashmap_get(call_info->iface_entry->method_handlers, call_info->method))) { 36153a5a1b3Sopenharmony_ci pa_assert_se(call_info->expected_method_sig = pa_hashmap_get(call_info->iface_entry->method_signatures, call_info->method)); 36253a5a1b3Sopenharmony_ci 36353a5a1b3Sopenharmony_ci if (pa_streq(call_info->method_sig, call_info->expected_method_sig)) 36453a5a1b3Sopenharmony_ci return FOUND_METHOD; 36553a5a1b3Sopenharmony_ci else 36653a5a1b3Sopenharmony_ci return INVALID_METHOD_SIG; 36753a5a1b3Sopenharmony_ci } 36853a5a1b3Sopenharmony_ci } 36953a5a1b3Sopenharmony_ci 37053a5a1b3Sopenharmony_ci return NO_SUCH_METHOD; 37153a5a1b3Sopenharmony_ci} 37253a5a1b3Sopenharmony_ci 37353a5a1b3Sopenharmony_cistatic enum find_result_t find_handler_from_properties_call(struct call_info *call_info) { 37453a5a1b3Sopenharmony_ci pa_assert(call_info); 37553a5a1b3Sopenharmony_ci 37653a5a1b3Sopenharmony_ci if (pa_streq(call_info->method, "GetAll")) { 37753a5a1b3Sopenharmony_ci call_info->expected_method_sig = "s"; 37853a5a1b3Sopenharmony_ci if (!pa_streq(call_info->method_sig, call_info->expected_method_sig)) 37953a5a1b3Sopenharmony_ci return INVALID_METHOD_SIG; 38053a5a1b3Sopenharmony_ci 38153a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_get_args(call_info->message, NULL, 38253a5a1b3Sopenharmony_ci DBUS_TYPE_STRING, &call_info->property_interface, 38353a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)); 38453a5a1b3Sopenharmony_ci 38553a5a1b3Sopenharmony_ci if (*call_info->property_interface) { 38653a5a1b3Sopenharmony_ci if ((call_info->iface_entry = pa_hashmap_get(call_info->obj_entry->interfaces, call_info->property_interface))) 38753a5a1b3Sopenharmony_ci return FOUND_GET_ALL; 38853a5a1b3Sopenharmony_ci else 38953a5a1b3Sopenharmony_ci return NO_SUCH_PROPERTY_INTERFACE; 39053a5a1b3Sopenharmony_ci 39153a5a1b3Sopenharmony_ci } else { 39253a5a1b3Sopenharmony_ci pa_assert_se(call_info->iface_entry = pa_hashmap_first(call_info->obj_entry->interfaces)); 39353a5a1b3Sopenharmony_ci return FOUND_GET_ALL; 39453a5a1b3Sopenharmony_ci } 39553a5a1b3Sopenharmony_ci 39653a5a1b3Sopenharmony_ci } else if (pa_streq(call_info->method, "Get")) { 39753a5a1b3Sopenharmony_ci call_info->expected_method_sig = "ss"; 39853a5a1b3Sopenharmony_ci if (!pa_streq(call_info->method_sig, call_info->expected_method_sig)) 39953a5a1b3Sopenharmony_ci return INVALID_METHOD_SIG; 40053a5a1b3Sopenharmony_ci 40153a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_get_args(call_info->message, NULL, 40253a5a1b3Sopenharmony_ci DBUS_TYPE_STRING, &call_info->property_interface, 40353a5a1b3Sopenharmony_ci DBUS_TYPE_STRING, &call_info->property, 40453a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)); 40553a5a1b3Sopenharmony_ci 40653a5a1b3Sopenharmony_ci if (*call_info->property_interface) { 40753a5a1b3Sopenharmony_ci if (!(call_info->iface_entry = pa_hashmap_get(call_info->obj_entry->interfaces, call_info->property_interface))) 40853a5a1b3Sopenharmony_ci return NO_SUCH_PROPERTY_INTERFACE; 40953a5a1b3Sopenharmony_ci else if ((call_info->property_handler = 41053a5a1b3Sopenharmony_ci pa_hashmap_get(call_info->iface_entry->property_handlers, call_info->property))) 41153a5a1b3Sopenharmony_ci return call_info->property_handler->get_cb ? FOUND_GET_PROPERTY : PROPERTY_ACCESS_DENIED; 41253a5a1b3Sopenharmony_ci else 41353a5a1b3Sopenharmony_ci return NO_SUCH_PROPERTY; 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_ci } else 41653a5a1b3Sopenharmony_ci return find_handler_by_property(call_info); 41753a5a1b3Sopenharmony_ci 41853a5a1b3Sopenharmony_ci } else if (pa_streq(call_info->method, "Set")) { 41953a5a1b3Sopenharmony_ci DBusMessageIter msg_iter; 42053a5a1b3Sopenharmony_ci 42153a5a1b3Sopenharmony_ci call_info->expected_method_sig = "ssv"; 42253a5a1b3Sopenharmony_ci if (!pa_streq(call_info->method_sig, call_info->expected_method_sig)) 42353a5a1b3Sopenharmony_ci return INVALID_METHOD_SIG; 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_init(call_info->message, &msg_iter)); 42653a5a1b3Sopenharmony_ci 42753a5a1b3Sopenharmony_ci dbus_message_iter_get_basic(&msg_iter, &call_info->property_interface); 42853a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_next(&msg_iter)); 42953a5a1b3Sopenharmony_ci dbus_message_iter_get_basic(&msg_iter, &call_info->property); 43053a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_next(&msg_iter)); 43153a5a1b3Sopenharmony_ci 43253a5a1b3Sopenharmony_ci dbus_message_iter_recurse(&msg_iter, &call_info->variant_iter); 43353a5a1b3Sopenharmony_ci 43453a5a1b3Sopenharmony_ci pa_assert_se(call_info->property_sig = dbus_message_iter_get_signature(&call_info->variant_iter)); 43553a5a1b3Sopenharmony_ci 43653a5a1b3Sopenharmony_ci if (*call_info->property_interface) { 43753a5a1b3Sopenharmony_ci if (!(call_info->iface_entry = pa_hashmap_get(call_info->obj_entry->interfaces, call_info->property_interface))) 43853a5a1b3Sopenharmony_ci return NO_SUCH_PROPERTY_INTERFACE; 43953a5a1b3Sopenharmony_ci 44053a5a1b3Sopenharmony_ci else if ((call_info->property_handler = 44153a5a1b3Sopenharmony_ci pa_hashmap_get(call_info->iface_entry->property_handlers, call_info->property))) { 44253a5a1b3Sopenharmony_ci call_info->expected_property_sig = call_info->property_handler->type; 44353a5a1b3Sopenharmony_ci 44453a5a1b3Sopenharmony_ci if (pa_streq(call_info->property_sig, call_info->expected_property_sig)) 44553a5a1b3Sopenharmony_ci return call_info->property_handler->set_cb ? FOUND_SET_PROPERTY : PROPERTY_ACCESS_DENIED; 44653a5a1b3Sopenharmony_ci else 44753a5a1b3Sopenharmony_ci return INVALID_PROPERTY_SIG; 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci } else 45053a5a1b3Sopenharmony_ci return NO_SUCH_PROPERTY; 45153a5a1b3Sopenharmony_ci 45253a5a1b3Sopenharmony_ci } else 45353a5a1b3Sopenharmony_ci return find_handler_by_property(call_info); 45453a5a1b3Sopenharmony_ci 45553a5a1b3Sopenharmony_ci } else 45653a5a1b3Sopenharmony_ci pa_assert_not_reached(); 45753a5a1b3Sopenharmony_ci} 45853a5a1b3Sopenharmony_ci 45953a5a1b3Sopenharmony_cistatic enum find_result_t find_handler(struct call_info *call_info) { 46053a5a1b3Sopenharmony_ci pa_assert(call_info); 46153a5a1b3Sopenharmony_ci 46253a5a1b3Sopenharmony_ci if (call_info->interface) { 46353a5a1b3Sopenharmony_ci if (pa_streq(call_info->interface, DBUS_INTERFACE_PROPERTIES)) 46453a5a1b3Sopenharmony_ci return find_handler_from_properties_call(call_info); 46553a5a1b3Sopenharmony_ci 46653a5a1b3Sopenharmony_ci else if (!(call_info->iface_entry = pa_hashmap_get(call_info->obj_entry->interfaces, call_info->interface))) 46753a5a1b3Sopenharmony_ci return NO_SUCH_INTERFACE; 46853a5a1b3Sopenharmony_ci 46953a5a1b3Sopenharmony_ci else if ((call_info->method_handler = pa_hashmap_get(call_info->iface_entry->method_handlers, call_info->method))) { 47053a5a1b3Sopenharmony_ci pa_assert_se(call_info->expected_method_sig = pa_hashmap_get(call_info->iface_entry->method_signatures, call_info->method)); 47153a5a1b3Sopenharmony_ci 47253a5a1b3Sopenharmony_ci if (!pa_streq(call_info->method_sig, call_info->expected_method_sig)) 47353a5a1b3Sopenharmony_ci return INVALID_METHOD_SIG; 47453a5a1b3Sopenharmony_ci 47553a5a1b3Sopenharmony_ci return FOUND_METHOD; 47653a5a1b3Sopenharmony_ci 47753a5a1b3Sopenharmony_ci } else 47853a5a1b3Sopenharmony_ci return NO_SUCH_METHOD; 47953a5a1b3Sopenharmony_ci 48053a5a1b3Sopenharmony_ci } else { /* The method call doesn't contain an interface. */ 48153a5a1b3Sopenharmony_ci if (pa_streq(call_info->method, "Get") || pa_streq(call_info->method, "Set") || pa_streq(call_info->method, "GetAll")) { 48253a5a1b3Sopenharmony_ci if (find_handler_by_method(call_info) == FOUND_METHOD) 48353a5a1b3Sopenharmony_ci /* The object has a method named Get, Set or GetAll in some other interface than .Properties. */ 48453a5a1b3Sopenharmony_ci return FOUND_METHOD; 48553a5a1b3Sopenharmony_ci else 48653a5a1b3Sopenharmony_ci /* Assume this is a .Properties call. */ 48753a5a1b3Sopenharmony_ci return find_handler_from_properties_call(call_info); 48853a5a1b3Sopenharmony_ci 48953a5a1b3Sopenharmony_ci } else /* This is not a .Properties call. */ 49053a5a1b3Sopenharmony_ci return find_handler_by_method(call_info); 49153a5a1b3Sopenharmony_ci } 49253a5a1b3Sopenharmony_ci} 49353a5a1b3Sopenharmony_ci 49453a5a1b3Sopenharmony_cistatic DBusHandlerResult handle_message_cb(DBusConnection *connection, DBusMessage *message, void *user_data) { 49553a5a1b3Sopenharmony_ci pa_dbus_protocol *p = user_data; 49653a5a1b3Sopenharmony_ci struct call_info call_info; 49753a5a1b3Sopenharmony_ci call_info.property_sig = NULL; 49853a5a1b3Sopenharmony_ci 49953a5a1b3Sopenharmony_ci pa_assert(connection); 50053a5a1b3Sopenharmony_ci pa_assert(message); 50153a5a1b3Sopenharmony_ci pa_assert(p); 50253a5a1b3Sopenharmony_ci pa_assert(p->objects); 50353a5a1b3Sopenharmony_ci 50453a5a1b3Sopenharmony_ci if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL) 50553a5a1b3Sopenharmony_ci return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 50653a5a1b3Sopenharmony_ci 50753a5a1b3Sopenharmony_ci pa_log_debug("Received message: destination = %s, interface = %s, member = %s", 50853a5a1b3Sopenharmony_ci dbus_message_get_path(message), 50953a5a1b3Sopenharmony_ci dbus_message_get_interface(message), 51053a5a1b3Sopenharmony_ci dbus_message_get_member(message)); 51153a5a1b3Sopenharmony_ci 51253a5a1b3Sopenharmony_ci call_info.message = message; 51353a5a1b3Sopenharmony_ci pa_assert_se(call_info.obj_entry = pa_hashmap_get(p->objects, dbus_message_get_path(message))); 51453a5a1b3Sopenharmony_ci call_info.interface = dbus_message_get_interface(message); 51553a5a1b3Sopenharmony_ci pa_assert_se(call_info.method = dbus_message_get_member(message)); 51653a5a1b3Sopenharmony_ci pa_assert_se(call_info.method_sig = dbus_message_get_signature(message)); 51753a5a1b3Sopenharmony_ci 51853a5a1b3Sopenharmony_ci if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect") || 51953a5a1b3Sopenharmony_ci (!dbus_message_get_interface(message) && dbus_message_has_member(message, "Introspect"))) { 52053a5a1b3Sopenharmony_ci pa_dbus_send_basic_value_reply(connection, message, DBUS_TYPE_STRING, &call_info.obj_entry->introspection); 52153a5a1b3Sopenharmony_ci goto finish; 52253a5a1b3Sopenharmony_ci } 52353a5a1b3Sopenharmony_ci 52453a5a1b3Sopenharmony_ci switch (find_handler(&call_info)) { 52553a5a1b3Sopenharmony_ci case FOUND_GET_PROPERTY: 52653a5a1b3Sopenharmony_ci call_info.property_handler->get_cb(connection, message, call_info.iface_entry->userdata); 52753a5a1b3Sopenharmony_ci break; 52853a5a1b3Sopenharmony_ci 52953a5a1b3Sopenharmony_ci case FOUND_SET_PROPERTY: 53053a5a1b3Sopenharmony_ci call_info.property_handler->set_cb(connection, message, &call_info.variant_iter, call_info.iface_entry->userdata); 53153a5a1b3Sopenharmony_ci break; 53253a5a1b3Sopenharmony_ci 53353a5a1b3Sopenharmony_ci case FOUND_METHOD: 53453a5a1b3Sopenharmony_ci call_info.method_handler->receive_cb(connection, message, call_info.iface_entry->userdata); 53553a5a1b3Sopenharmony_ci break; 53653a5a1b3Sopenharmony_ci 53753a5a1b3Sopenharmony_ci case FOUND_GET_ALL: 53853a5a1b3Sopenharmony_ci if (call_info.iface_entry->get_all_properties_cb) 53953a5a1b3Sopenharmony_ci call_info.iface_entry->get_all_properties_cb(connection, message, call_info.iface_entry->userdata); 54053a5a1b3Sopenharmony_ci else { 54153a5a1b3Sopenharmony_ci DBusMessage *dummy_reply = NULL; 54253a5a1b3Sopenharmony_ci DBusMessageIter msg_iter; 54353a5a1b3Sopenharmony_ci DBusMessageIter dict_iter; 54453a5a1b3Sopenharmony_ci 54553a5a1b3Sopenharmony_ci pa_assert_se(dummy_reply = dbus_message_new_method_return(message)); 54653a5a1b3Sopenharmony_ci dbus_message_iter_init_append(dummy_reply, &msg_iter); 54753a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)); 54853a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter)); 54953a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_send(connection, dummy_reply, NULL)); 55053a5a1b3Sopenharmony_ci dbus_message_unref(dummy_reply); 55153a5a1b3Sopenharmony_ci } 55253a5a1b3Sopenharmony_ci break; 55353a5a1b3Sopenharmony_ci 55453a5a1b3Sopenharmony_ci case PROPERTY_ACCESS_DENIED: 55553a5a1b3Sopenharmony_ci pa_dbus_send_error(connection, message, DBUS_ERROR_ACCESS_DENIED, 55653a5a1b3Sopenharmony_ci "%s access denied for property %s", call_info.method, call_info.property); 55753a5a1b3Sopenharmony_ci break; 55853a5a1b3Sopenharmony_ci 55953a5a1b3Sopenharmony_ci case NO_SUCH_METHOD: 56053a5a1b3Sopenharmony_ci pa_dbus_send_error(connection, message, DBUS_ERROR_UNKNOWN_METHOD, "No such method: %s", call_info.method); 56153a5a1b3Sopenharmony_ci break; 56253a5a1b3Sopenharmony_ci 56353a5a1b3Sopenharmony_ci case NO_SUCH_INTERFACE: 56453a5a1b3Sopenharmony_ci pa_dbus_send_error(connection, message, PA_DBUS_ERROR_NO_SUCH_INTERFACE, "No such interface: %s", call_info.interface); 56553a5a1b3Sopenharmony_ci break; 56653a5a1b3Sopenharmony_ci 56753a5a1b3Sopenharmony_ci case NO_SUCH_PROPERTY: 56853a5a1b3Sopenharmony_ci pa_dbus_send_error(connection, message, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "No such property: %s", call_info.property); 56953a5a1b3Sopenharmony_ci break; 57053a5a1b3Sopenharmony_ci 57153a5a1b3Sopenharmony_ci case NO_SUCH_PROPERTY_INTERFACE: 57253a5a1b3Sopenharmony_ci pa_dbus_send_error(connection, message, PA_DBUS_ERROR_NO_SUCH_INTERFACE, "No such property interface: %s", call_info.property_interface); 57353a5a1b3Sopenharmony_ci break; 57453a5a1b3Sopenharmony_ci 57553a5a1b3Sopenharmony_ci case INVALID_METHOD_SIG: 57653a5a1b3Sopenharmony_ci pa_dbus_send_error(connection, message, DBUS_ERROR_INVALID_ARGS, 57753a5a1b3Sopenharmony_ci "Invalid signature for method %s: '%s'. Expected '%s'.", 57853a5a1b3Sopenharmony_ci call_info.method, call_info.method_sig, call_info.expected_method_sig); 57953a5a1b3Sopenharmony_ci break; 58053a5a1b3Sopenharmony_ci 58153a5a1b3Sopenharmony_ci case INVALID_PROPERTY_SIG: 58253a5a1b3Sopenharmony_ci pa_dbus_send_error(connection, message, DBUS_ERROR_INVALID_ARGS, 58353a5a1b3Sopenharmony_ci "Invalid signature for property %s: '%s'. Expected '%s'.", 58453a5a1b3Sopenharmony_ci call_info.property, call_info.property_sig, call_info.expected_property_sig); 58553a5a1b3Sopenharmony_ci break; 58653a5a1b3Sopenharmony_ci 58753a5a1b3Sopenharmony_ci default: 58853a5a1b3Sopenharmony_ci pa_assert_not_reached(); 58953a5a1b3Sopenharmony_ci } 59053a5a1b3Sopenharmony_ci 59153a5a1b3Sopenharmony_cifinish: 59253a5a1b3Sopenharmony_ci if (call_info.property_sig) 59353a5a1b3Sopenharmony_ci dbus_free(call_info.property_sig); 59453a5a1b3Sopenharmony_ci 59553a5a1b3Sopenharmony_ci return DBUS_HANDLER_RESULT_HANDLED; 59653a5a1b3Sopenharmony_ci} 59753a5a1b3Sopenharmony_ci 59853a5a1b3Sopenharmony_cistatic DBusObjectPathVTable vtable = { 59953a5a1b3Sopenharmony_ci .unregister_function = NULL, 60053a5a1b3Sopenharmony_ci .message_function = handle_message_cb, 60153a5a1b3Sopenharmony_ci .dbus_internal_pad1 = NULL, 60253a5a1b3Sopenharmony_ci .dbus_internal_pad2 = NULL, 60353a5a1b3Sopenharmony_ci .dbus_internal_pad3 = NULL, 60453a5a1b3Sopenharmony_ci .dbus_internal_pad4 = NULL 60553a5a1b3Sopenharmony_ci}; 60653a5a1b3Sopenharmony_ci 60753a5a1b3Sopenharmony_cistatic void register_object(pa_dbus_protocol *p, struct object_entry *obj_entry) { 60853a5a1b3Sopenharmony_ci struct connection_entry *conn_entry; 60953a5a1b3Sopenharmony_ci void *state = NULL; 61053a5a1b3Sopenharmony_ci 61153a5a1b3Sopenharmony_ci pa_assert(p); 61253a5a1b3Sopenharmony_ci pa_assert(obj_entry); 61353a5a1b3Sopenharmony_ci 61453a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(conn_entry, p->connections, state) 61553a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_register_object_path(conn_entry->connection, obj_entry->path, &vtable, p)); 61653a5a1b3Sopenharmony_ci} 61753a5a1b3Sopenharmony_ci 61853a5a1b3Sopenharmony_cistatic pa_dbus_arg_info *copy_args(const pa_dbus_arg_info *src, unsigned n) { 61953a5a1b3Sopenharmony_ci pa_dbus_arg_info *dst; 62053a5a1b3Sopenharmony_ci unsigned i; 62153a5a1b3Sopenharmony_ci 62253a5a1b3Sopenharmony_ci if (n == 0) 62353a5a1b3Sopenharmony_ci return NULL; 62453a5a1b3Sopenharmony_ci 62553a5a1b3Sopenharmony_ci pa_assert(src); 62653a5a1b3Sopenharmony_ci 62753a5a1b3Sopenharmony_ci dst = pa_xnew0(pa_dbus_arg_info, n); 62853a5a1b3Sopenharmony_ci 62953a5a1b3Sopenharmony_ci for (i = 0; i < n; ++i) { 63053a5a1b3Sopenharmony_ci dst[i].name = pa_xstrdup(src[i].name); 63153a5a1b3Sopenharmony_ci dst[i].type = pa_xstrdup(src[i].type); 63253a5a1b3Sopenharmony_ci dst[i].direction = pa_xstrdup(src[i].direction); 63353a5a1b3Sopenharmony_ci } 63453a5a1b3Sopenharmony_ci 63553a5a1b3Sopenharmony_ci return dst; 63653a5a1b3Sopenharmony_ci} 63753a5a1b3Sopenharmony_ci 63853a5a1b3Sopenharmony_cistatic void method_handler_free(pa_dbus_method_handler *h) { 63953a5a1b3Sopenharmony_ci unsigned i; 64053a5a1b3Sopenharmony_ci 64153a5a1b3Sopenharmony_ci pa_assert(h); 64253a5a1b3Sopenharmony_ci 64353a5a1b3Sopenharmony_ci pa_xfree((char *) h->method_name); 64453a5a1b3Sopenharmony_ci 64553a5a1b3Sopenharmony_ci for (i = 0; i < h->n_arguments; ++i) { 64653a5a1b3Sopenharmony_ci pa_xfree((char *) h->arguments[i].name); 64753a5a1b3Sopenharmony_ci pa_xfree((char *) h->arguments[i].type); 64853a5a1b3Sopenharmony_ci pa_xfree((char *) h->arguments[i].direction); 64953a5a1b3Sopenharmony_ci } 65053a5a1b3Sopenharmony_ci 65153a5a1b3Sopenharmony_ci pa_xfree((pa_dbus_arg_info *) h->arguments); 65253a5a1b3Sopenharmony_ci pa_xfree(h); 65353a5a1b3Sopenharmony_ci} 65453a5a1b3Sopenharmony_ci 65553a5a1b3Sopenharmony_cistatic pa_hashmap *create_method_handlers(const pa_dbus_interface_info *info) { 65653a5a1b3Sopenharmony_ci pa_hashmap *handlers; 65753a5a1b3Sopenharmony_ci unsigned i; 65853a5a1b3Sopenharmony_ci 65953a5a1b3Sopenharmony_ci pa_assert(info); 66053a5a1b3Sopenharmony_ci pa_assert(info->method_handlers || info->n_method_handlers == 0); 66153a5a1b3Sopenharmony_ci 66253a5a1b3Sopenharmony_ci handlers = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) method_handler_free); 66353a5a1b3Sopenharmony_ci 66453a5a1b3Sopenharmony_ci for (i = 0; i < info->n_method_handlers; ++i) { 66553a5a1b3Sopenharmony_ci pa_dbus_method_handler *h = pa_xnew(pa_dbus_method_handler, 1); 66653a5a1b3Sopenharmony_ci h->method_name = pa_xstrdup(info->method_handlers[i].method_name); 66753a5a1b3Sopenharmony_ci h->arguments = copy_args(info->method_handlers[i].arguments, info->method_handlers[i].n_arguments); 66853a5a1b3Sopenharmony_ci h->n_arguments = info->method_handlers[i].n_arguments; 66953a5a1b3Sopenharmony_ci h->receive_cb = info->method_handlers[i].receive_cb; 67053a5a1b3Sopenharmony_ci 67153a5a1b3Sopenharmony_ci pa_hashmap_put(handlers, (char *) h->method_name, h); 67253a5a1b3Sopenharmony_ci } 67353a5a1b3Sopenharmony_ci 67453a5a1b3Sopenharmony_ci return handlers; 67553a5a1b3Sopenharmony_ci} 67653a5a1b3Sopenharmony_ci 67753a5a1b3Sopenharmony_cistatic pa_hashmap *extract_method_signatures(pa_hashmap *method_handlers) { 67853a5a1b3Sopenharmony_ci pa_hashmap *signatures = NULL; 67953a5a1b3Sopenharmony_ci pa_dbus_method_handler *handler = NULL; 68053a5a1b3Sopenharmony_ci void *state = NULL; 68153a5a1b3Sopenharmony_ci pa_strbuf *sig_buf = NULL; 68253a5a1b3Sopenharmony_ci unsigned i = 0; 68353a5a1b3Sopenharmony_ci 68453a5a1b3Sopenharmony_ci pa_assert(method_handlers); 68553a5a1b3Sopenharmony_ci 68653a5a1b3Sopenharmony_ci signatures = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree); 68753a5a1b3Sopenharmony_ci 68853a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(handler, method_handlers, state) { 68953a5a1b3Sopenharmony_ci sig_buf = pa_strbuf_new(); 69053a5a1b3Sopenharmony_ci 69153a5a1b3Sopenharmony_ci for (i = 0; i < handler->n_arguments; ++i) { 69253a5a1b3Sopenharmony_ci if (pa_streq(handler->arguments[i].direction, "in")) 69353a5a1b3Sopenharmony_ci pa_strbuf_puts(sig_buf, handler->arguments[i].type); 69453a5a1b3Sopenharmony_ci } 69553a5a1b3Sopenharmony_ci 69653a5a1b3Sopenharmony_ci pa_hashmap_put(signatures, (char *) handler->method_name, pa_strbuf_to_string_free(sig_buf)); 69753a5a1b3Sopenharmony_ci } 69853a5a1b3Sopenharmony_ci 69953a5a1b3Sopenharmony_ci return signatures; 70053a5a1b3Sopenharmony_ci} 70153a5a1b3Sopenharmony_ci 70253a5a1b3Sopenharmony_cistatic void property_handler_free(pa_dbus_property_handler *h) { 70353a5a1b3Sopenharmony_ci pa_assert(h); 70453a5a1b3Sopenharmony_ci 70553a5a1b3Sopenharmony_ci pa_xfree((char *) h->property_name); 70653a5a1b3Sopenharmony_ci pa_xfree((char *) h->type); 70753a5a1b3Sopenharmony_ci 70853a5a1b3Sopenharmony_ci pa_xfree(h); 70953a5a1b3Sopenharmony_ci} 71053a5a1b3Sopenharmony_ci 71153a5a1b3Sopenharmony_cistatic pa_hashmap *create_property_handlers(const pa_dbus_interface_info *info) { 71253a5a1b3Sopenharmony_ci pa_hashmap *handlers; 71353a5a1b3Sopenharmony_ci unsigned i = 0; 71453a5a1b3Sopenharmony_ci 71553a5a1b3Sopenharmony_ci pa_assert(info); 71653a5a1b3Sopenharmony_ci pa_assert(info->property_handlers || info->n_property_handlers == 0); 71753a5a1b3Sopenharmony_ci 71853a5a1b3Sopenharmony_ci handlers = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) property_handler_free); 71953a5a1b3Sopenharmony_ci 72053a5a1b3Sopenharmony_ci for (i = 0; i < info->n_property_handlers; ++i) { 72153a5a1b3Sopenharmony_ci pa_dbus_property_handler *h = pa_xnew(pa_dbus_property_handler, 1); 72253a5a1b3Sopenharmony_ci h->property_name = pa_xstrdup(info->property_handlers[i].property_name); 72353a5a1b3Sopenharmony_ci h->type = pa_xstrdup(info->property_handlers[i].type); 72453a5a1b3Sopenharmony_ci h->get_cb = info->property_handlers[i].get_cb; 72553a5a1b3Sopenharmony_ci h->set_cb = info->property_handlers[i].set_cb; 72653a5a1b3Sopenharmony_ci 72753a5a1b3Sopenharmony_ci pa_hashmap_put(handlers, (char *) h->property_name, h); 72853a5a1b3Sopenharmony_ci } 72953a5a1b3Sopenharmony_ci 73053a5a1b3Sopenharmony_ci return handlers; 73153a5a1b3Sopenharmony_ci} 73253a5a1b3Sopenharmony_ci 73353a5a1b3Sopenharmony_cistatic pa_dbus_signal_info *copy_signals(const pa_dbus_interface_info *info) { 73453a5a1b3Sopenharmony_ci pa_dbus_signal_info *dst; 73553a5a1b3Sopenharmony_ci unsigned i; 73653a5a1b3Sopenharmony_ci 73753a5a1b3Sopenharmony_ci pa_assert(info); 73853a5a1b3Sopenharmony_ci 73953a5a1b3Sopenharmony_ci if (info->n_signals == 0) 74053a5a1b3Sopenharmony_ci return NULL; 74153a5a1b3Sopenharmony_ci 74253a5a1b3Sopenharmony_ci pa_assert(info->signals); 74353a5a1b3Sopenharmony_ci 74453a5a1b3Sopenharmony_ci dst = pa_xnew(pa_dbus_signal_info, info->n_signals); 74553a5a1b3Sopenharmony_ci 74653a5a1b3Sopenharmony_ci for (i = 0; i < info->n_signals; ++i) { 74753a5a1b3Sopenharmony_ci dst[i].name = pa_xstrdup(info->signals[i].name); 74853a5a1b3Sopenharmony_ci dst[i].arguments = copy_args(info->signals[i].arguments, info->signals[i].n_arguments); 74953a5a1b3Sopenharmony_ci dst[i].n_arguments = info->signals[i].n_arguments; 75053a5a1b3Sopenharmony_ci } 75153a5a1b3Sopenharmony_ci 75253a5a1b3Sopenharmony_ci return dst; 75353a5a1b3Sopenharmony_ci} 75453a5a1b3Sopenharmony_ci 75553a5a1b3Sopenharmony_ciint pa_dbus_protocol_add_interface(pa_dbus_protocol *p, 75653a5a1b3Sopenharmony_ci const char *path, 75753a5a1b3Sopenharmony_ci const pa_dbus_interface_info *info, 75853a5a1b3Sopenharmony_ci void *userdata) { 75953a5a1b3Sopenharmony_ci struct object_entry *obj_entry; 76053a5a1b3Sopenharmony_ci struct interface_entry *iface_entry; 76153a5a1b3Sopenharmony_ci bool obj_entry_created = false; 76253a5a1b3Sopenharmony_ci 76353a5a1b3Sopenharmony_ci pa_assert(p); 76453a5a1b3Sopenharmony_ci pa_assert(path); 76553a5a1b3Sopenharmony_ci pa_assert(info); 76653a5a1b3Sopenharmony_ci pa_assert(info->name); 76753a5a1b3Sopenharmony_ci pa_assert(info->method_handlers || info->n_method_handlers == 0); 76853a5a1b3Sopenharmony_ci pa_assert(info->property_handlers || info->n_property_handlers == 0); 76953a5a1b3Sopenharmony_ci pa_assert(info->get_all_properties_cb || info->n_property_handlers == 0); 77053a5a1b3Sopenharmony_ci pa_assert(info->signals || info->n_signals == 0); 77153a5a1b3Sopenharmony_ci 77253a5a1b3Sopenharmony_ci if (!(obj_entry = pa_hashmap_get(p->objects, path))) { 77353a5a1b3Sopenharmony_ci obj_entry = pa_xnew(struct object_entry, 1); 77453a5a1b3Sopenharmony_ci obj_entry->path = pa_xstrdup(path); 77553a5a1b3Sopenharmony_ci obj_entry->interfaces = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); 77653a5a1b3Sopenharmony_ci obj_entry->introspection = NULL; 77753a5a1b3Sopenharmony_ci 77853a5a1b3Sopenharmony_ci pa_hashmap_put(p->objects, obj_entry->path, obj_entry); 77953a5a1b3Sopenharmony_ci obj_entry_created = true; 78053a5a1b3Sopenharmony_ci } 78153a5a1b3Sopenharmony_ci 78253a5a1b3Sopenharmony_ci if (pa_hashmap_get(obj_entry->interfaces, info->name) != NULL) 78353a5a1b3Sopenharmony_ci goto fail; /* The interface was already registered. */ 78453a5a1b3Sopenharmony_ci 78553a5a1b3Sopenharmony_ci iface_entry = pa_xnew(struct interface_entry, 1); 78653a5a1b3Sopenharmony_ci iface_entry->name = pa_xstrdup(info->name); 78753a5a1b3Sopenharmony_ci iface_entry->method_handlers = create_method_handlers(info); 78853a5a1b3Sopenharmony_ci iface_entry->method_signatures = extract_method_signatures(iface_entry->method_handlers); 78953a5a1b3Sopenharmony_ci iface_entry->property_handlers = create_property_handlers(info); 79053a5a1b3Sopenharmony_ci iface_entry->get_all_properties_cb = info->get_all_properties_cb; 79153a5a1b3Sopenharmony_ci iface_entry->signals = copy_signals(info); 79253a5a1b3Sopenharmony_ci iface_entry->n_signals = info->n_signals; 79353a5a1b3Sopenharmony_ci iface_entry->userdata = userdata; 79453a5a1b3Sopenharmony_ci pa_hashmap_put(obj_entry->interfaces, iface_entry->name, iface_entry); 79553a5a1b3Sopenharmony_ci 79653a5a1b3Sopenharmony_ci update_introspection(obj_entry); 79753a5a1b3Sopenharmony_ci 79853a5a1b3Sopenharmony_ci if (obj_entry_created) 79953a5a1b3Sopenharmony_ci register_object(p, obj_entry); 80053a5a1b3Sopenharmony_ci 80153a5a1b3Sopenharmony_ci pa_log_debug("Interface %s added for object %s", iface_entry->name, obj_entry->path); 80253a5a1b3Sopenharmony_ci 80353a5a1b3Sopenharmony_ci return 0; 80453a5a1b3Sopenharmony_ci 80553a5a1b3Sopenharmony_cifail: 80653a5a1b3Sopenharmony_ci return -1; 80753a5a1b3Sopenharmony_ci} 80853a5a1b3Sopenharmony_ci 80953a5a1b3Sopenharmony_cistatic void unregister_object(pa_dbus_protocol *p, struct object_entry *obj_entry) { 81053a5a1b3Sopenharmony_ci struct connection_entry *conn_entry; 81153a5a1b3Sopenharmony_ci void *state = NULL; 81253a5a1b3Sopenharmony_ci 81353a5a1b3Sopenharmony_ci pa_assert(p); 81453a5a1b3Sopenharmony_ci pa_assert(obj_entry); 81553a5a1b3Sopenharmony_ci 81653a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(conn_entry, p->connections, state) 81753a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_unregister_object_path(conn_entry->connection, obj_entry->path)); 81853a5a1b3Sopenharmony_ci} 81953a5a1b3Sopenharmony_ci 82053a5a1b3Sopenharmony_ciint pa_dbus_protocol_remove_interface(pa_dbus_protocol *p, const char* path, const char* interface) { 82153a5a1b3Sopenharmony_ci struct object_entry *obj_entry; 82253a5a1b3Sopenharmony_ci struct interface_entry *iface_entry; 82353a5a1b3Sopenharmony_ci unsigned i; 82453a5a1b3Sopenharmony_ci 82553a5a1b3Sopenharmony_ci pa_assert(p); 82653a5a1b3Sopenharmony_ci pa_assert(path); 82753a5a1b3Sopenharmony_ci pa_assert(interface); 82853a5a1b3Sopenharmony_ci 82953a5a1b3Sopenharmony_ci if (!(obj_entry = pa_hashmap_get(p->objects, path))) 83053a5a1b3Sopenharmony_ci return -1; 83153a5a1b3Sopenharmony_ci 83253a5a1b3Sopenharmony_ci if (!(iface_entry = pa_hashmap_remove(obj_entry->interfaces, interface))) 83353a5a1b3Sopenharmony_ci return -1; 83453a5a1b3Sopenharmony_ci 83553a5a1b3Sopenharmony_ci update_introspection(obj_entry); 83653a5a1b3Sopenharmony_ci 83753a5a1b3Sopenharmony_ci pa_log_debug("Interface %s removed from object %s", iface_entry->name, obj_entry->path); 83853a5a1b3Sopenharmony_ci 83953a5a1b3Sopenharmony_ci pa_xfree(iface_entry->name); 84053a5a1b3Sopenharmony_ci pa_hashmap_free(iface_entry->method_signatures); 84153a5a1b3Sopenharmony_ci pa_hashmap_free(iface_entry->method_handlers); 84253a5a1b3Sopenharmony_ci pa_hashmap_free(iface_entry->property_handlers); 84353a5a1b3Sopenharmony_ci 84453a5a1b3Sopenharmony_ci for (i = 0; i < iface_entry->n_signals; ++i) { 84553a5a1b3Sopenharmony_ci unsigned j; 84653a5a1b3Sopenharmony_ci 84753a5a1b3Sopenharmony_ci pa_xfree((char *) iface_entry->signals[i].name); 84853a5a1b3Sopenharmony_ci 84953a5a1b3Sopenharmony_ci for (j = 0; j < iface_entry->signals[i].n_arguments; ++j) { 85053a5a1b3Sopenharmony_ci pa_xfree((char *) iface_entry->signals[i].arguments[j].name); 85153a5a1b3Sopenharmony_ci pa_xfree((char *) iface_entry->signals[i].arguments[j].type); 85253a5a1b3Sopenharmony_ci pa_assert(iface_entry->signals[i].arguments[j].direction == NULL); 85353a5a1b3Sopenharmony_ci } 85453a5a1b3Sopenharmony_ci 85553a5a1b3Sopenharmony_ci pa_xfree((pa_dbus_arg_info *) iface_entry->signals[i].arguments); 85653a5a1b3Sopenharmony_ci } 85753a5a1b3Sopenharmony_ci 85853a5a1b3Sopenharmony_ci pa_xfree(iface_entry->signals); 85953a5a1b3Sopenharmony_ci pa_xfree(iface_entry); 86053a5a1b3Sopenharmony_ci 86153a5a1b3Sopenharmony_ci if (pa_hashmap_isempty(obj_entry->interfaces)) { 86253a5a1b3Sopenharmony_ci unregister_object(p, obj_entry); 86353a5a1b3Sopenharmony_ci 86453a5a1b3Sopenharmony_ci pa_hashmap_remove(p->objects, path); 86553a5a1b3Sopenharmony_ci pa_xfree(obj_entry->path); 86653a5a1b3Sopenharmony_ci pa_hashmap_free(obj_entry->interfaces); 86753a5a1b3Sopenharmony_ci pa_xfree(obj_entry->introspection); 86853a5a1b3Sopenharmony_ci pa_xfree(obj_entry); 86953a5a1b3Sopenharmony_ci } 87053a5a1b3Sopenharmony_ci 87153a5a1b3Sopenharmony_ci return 0; 87253a5a1b3Sopenharmony_ci} 87353a5a1b3Sopenharmony_ci 87453a5a1b3Sopenharmony_cistatic void register_all_objects(pa_dbus_protocol *p, DBusConnection *conn) { 87553a5a1b3Sopenharmony_ci struct object_entry *obj_entry; 87653a5a1b3Sopenharmony_ci void *state = NULL; 87753a5a1b3Sopenharmony_ci 87853a5a1b3Sopenharmony_ci pa_assert(p); 87953a5a1b3Sopenharmony_ci pa_assert(conn); 88053a5a1b3Sopenharmony_ci 88153a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(obj_entry, p->objects, state) 88253a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_register_object_path(conn, obj_entry->path, &vtable, p)); 88353a5a1b3Sopenharmony_ci} 88453a5a1b3Sopenharmony_ci 88553a5a1b3Sopenharmony_cistatic void signal_paths_entry_free(struct signal_paths_entry *e) { 88653a5a1b3Sopenharmony_ci pa_assert(e); 88753a5a1b3Sopenharmony_ci 88853a5a1b3Sopenharmony_ci pa_xfree(e->signal); 88953a5a1b3Sopenharmony_ci pa_idxset_free(e->paths, pa_xfree); 89053a5a1b3Sopenharmony_ci pa_xfree(e); 89153a5a1b3Sopenharmony_ci} 89253a5a1b3Sopenharmony_ci 89353a5a1b3Sopenharmony_ciint pa_dbus_protocol_register_connection(pa_dbus_protocol *p, DBusConnection *conn, pa_client *client) { 89453a5a1b3Sopenharmony_ci struct connection_entry *conn_entry; 89553a5a1b3Sopenharmony_ci 89653a5a1b3Sopenharmony_ci pa_assert(p); 89753a5a1b3Sopenharmony_ci pa_assert(conn); 89853a5a1b3Sopenharmony_ci pa_assert(client); 89953a5a1b3Sopenharmony_ci 90053a5a1b3Sopenharmony_ci if (pa_hashmap_get(p->connections, conn)) 90153a5a1b3Sopenharmony_ci return -1; /* The connection was already registered. */ 90253a5a1b3Sopenharmony_ci 90353a5a1b3Sopenharmony_ci register_all_objects(p, conn); 90453a5a1b3Sopenharmony_ci 90553a5a1b3Sopenharmony_ci conn_entry = pa_xnew(struct connection_entry, 1); 90653a5a1b3Sopenharmony_ci conn_entry->connection = dbus_connection_ref(conn); 90753a5a1b3Sopenharmony_ci conn_entry->client = client; 90853a5a1b3Sopenharmony_ci conn_entry->listening_for_all_signals = false; 90953a5a1b3Sopenharmony_ci conn_entry->all_signals_objects = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); 91053a5a1b3Sopenharmony_ci conn_entry->listening_signals = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, 91153a5a1b3Sopenharmony_ci (pa_free_cb_t) signal_paths_entry_free); 91253a5a1b3Sopenharmony_ci 91353a5a1b3Sopenharmony_ci pa_hashmap_put(p->connections, conn, conn_entry); 91453a5a1b3Sopenharmony_ci 91553a5a1b3Sopenharmony_ci return 0; 91653a5a1b3Sopenharmony_ci} 91753a5a1b3Sopenharmony_ci 91853a5a1b3Sopenharmony_cistatic void unregister_all_objects(pa_dbus_protocol *p, DBusConnection *conn) { 91953a5a1b3Sopenharmony_ci struct object_entry *obj_entry; 92053a5a1b3Sopenharmony_ci void *state = NULL; 92153a5a1b3Sopenharmony_ci 92253a5a1b3Sopenharmony_ci pa_assert(p); 92353a5a1b3Sopenharmony_ci pa_assert(conn); 92453a5a1b3Sopenharmony_ci 92553a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(obj_entry, p->objects, state) 92653a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_unregister_object_path(conn, obj_entry->path)); 92753a5a1b3Sopenharmony_ci} 92853a5a1b3Sopenharmony_ci 92953a5a1b3Sopenharmony_cistatic struct signal_paths_entry *signal_paths_entry_new(const char *signal_name) { 93053a5a1b3Sopenharmony_ci struct signal_paths_entry *e = NULL; 93153a5a1b3Sopenharmony_ci 93253a5a1b3Sopenharmony_ci pa_assert(signal_name); 93353a5a1b3Sopenharmony_ci 93453a5a1b3Sopenharmony_ci e = pa_xnew0(struct signal_paths_entry, 1); 93553a5a1b3Sopenharmony_ci e->signal = pa_xstrdup(signal_name); 93653a5a1b3Sopenharmony_ci e->paths = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); 93753a5a1b3Sopenharmony_ci 93853a5a1b3Sopenharmony_ci return e; 93953a5a1b3Sopenharmony_ci} 94053a5a1b3Sopenharmony_ci 94153a5a1b3Sopenharmony_ciint pa_dbus_protocol_unregister_connection(pa_dbus_protocol *p, DBusConnection *conn) { 94253a5a1b3Sopenharmony_ci struct connection_entry *conn_entry = NULL; 94353a5a1b3Sopenharmony_ci 94453a5a1b3Sopenharmony_ci pa_assert(p); 94553a5a1b3Sopenharmony_ci pa_assert(conn); 94653a5a1b3Sopenharmony_ci 94753a5a1b3Sopenharmony_ci if (!(conn_entry = pa_hashmap_remove(p->connections, conn))) 94853a5a1b3Sopenharmony_ci return -1; 94953a5a1b3Sopenharmony_ci 95053a5a1b3Sopenharmony_ci unregister_all_objects(p, conn); 95153a5a1b3Sopenharmony_ci 95253a5a1b3Sopenharmony_ci dbus_connection_unref(conn_entry->connection); 95353a5a1b3Sopenharmony_ci pa_idxset_free(conn_entry->all_signals_objects, pa_xfree); 95453a5a1b3Sopenharmony_ci pa_hashmap_free(conn_entry->listening_signals); 95553a5a1b3Sopenharmony_ci pa_xfree(conn_entry); 95653a5a1b3Sopenharmony_ci 95753a5a1b3Sopenharmony_ci return 0; 95853a5a1b3Sopenharmony_ci} 95953a5a1b3Sopenharmony_ci 96053a5a1b3Sopenharmony_cipa_client *pa_dbus_protocol_get_client(pa_dbus_protocol *p, DBusConnection *conn) { 96153a5a1b3Sopenharmony_ci struct connection_entry *conn_entry; 96253a5a1b3Sopenharmony_ci 96353a5a1b3Sopenharmony_ci pa_assert(p); 96453a5a1b3Sopenharmony_ci pa_assert(conn); 96553a5a1b3Sopenharmony_ci 96653a5a1b3Sopenharmony_ci if (!(conn_entry = pa_hashmap_get(p->connections, conn))) 96753a5a1b3Sopenharmony_ci return NULL; 96853a5a1b3Sopenharmony_ci 96953a5a1b3Sopenharmony_ci return conn_entry->client; 97053a5a1b3Sopenharmony_ci} 97153a5a1b3Sopenharmony_ci 97253a5a1b3Sopenharmony_civoid pa_dbus_protocol_add_signal_listener( 97353a5a1b3Sopenharmony_ci pa_dbus_protocol *p, 97453a5a1b3Sopenharmony_ci DBusConnection *conn, 97553a5a1b3Sopenharmony_ci const char *signal_name, 97653a5a1b3Sopenharmony_ci char **objects, 97753a5a1b3Sopenharmony_ci unsigned n_objects) { 97853a5a1b3Sopenharmony_ci struct connection_entry *conn_entry = NULL; 97953a5a1b3Sopenharmony_ci struct signal_paths_entry *signal_paths_entry = NULL; 98053a5a1b3Sopenharmony_ci unsigned i = 0; 98153a5a1b3Sopenharmony_ci 98253a5a1b3Sopenharmony_ci pa_assert(p); 98353a5a1b3Sopenharmony_ci pa_assert(conn); 98453a5a1b3Sopenharmony_ci pa_assert(objects || n_objects == 0); 98553a5a1b3Sopenharmony_ci 98653a5a1b3Sopenharmony_ci pa_assert_se((conn_entry = pa_hashmap_get(p->connections, conn))); 98753a5a1b3Sopenharmony_ci 98853a5a1b3Sopenharmony_ci /* all_signals_objects will either be emptied or replaced with new objects, 98953a5a1b3Sopenharmony_ci * so we empty it here unconditionally. If listening_for_all_signals is 99053a5a1b3Sopenharmony_ci * currently false, the idxset is empty already so this does nothing. */ 99153a5a1b3Sopenharmony_ci pa_idxset_remove_all(conn_entry->all_signals_objects, pa_xfree); 99253a5a1b3Sopenharmony_ci 99353a5a1b3Sopenharmony_ci if (signal_name) { 99453a5a1b3Sopenharmony_ci conn_entry->listening_for_all_signals = false; 99553a5a1b3Sopenharmony_ci 99653a5a1b3Sopenharmony_ci /* Replace the old signal paths entry for this signal with a new 99753a5a1b3Sopenharmony_ci * one. */ 99853a5a1b3Sopenharmony_ci pa_hashmap_remove_and_free(conn_entry->listening_signals, signal_name); 99953a5a1b3Sopenharmony_ci signal_paths_entry = signal_paths_entry_new(signal_name); 100053a5a1b3Sopenharmony_ci 100153a5a1b3Sopenharmony_ci for (i = 0; i < n_objects; ++i) 100253a5a1b3Sopenharmony_ci pa_idxset_put(signal_paths_entry->paths, pa_xstrdup(objects[i]), NULL); 100353a5a1b3Sopenharmony_ci 100453a5a1b3Sopenharmony_ci pa_hashmap_put(conn_entry->listening_signals, signal_paths_entry->signal, signal_paths_entry); 100553a5a1b3Sopenharmony_ci 100653a5a1b3Sopenharmony_ci } else { 100753a5a1b3Sopenharmony_ci conn_entry->listening_for_all_signals = true; 100853a5a1b3Sopenharmony_ci 100953a5a1b3Sopenharmony_ci /* We're not interested in individual signals anymore, so let's empty 101053a5a1b3Sopenharmony_ci * listening_signals. */ 101153a5a1b3Sopenharmony_ci pa_hashmap_remove_all(conn_entry->listening_signals); 101253a5a1b3Sopenharmony_ci 101353a5a1b3Sopenharmony_ci for (i = 0; i < n_objects; ++i) 101453a5a1b3Sopenharmony_ci pa_idxset_put(conn_entry->all_signals_objects, pa_xstrdup(objects[i]), NULL); 101553a5a1b3Sopenharmony_ci } 101653a5a1b3Sopenharmony_ci} 101753a5a1b3Sopenharmony_ci 101853a5a1b3Sopenharmony_civoid pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection *conn, const char *signal_name) { 101953a5a1b3Sopenharmony_ci struct connection_entry *conn_entry = NULL; 102053a5a1b3Sopenharmony_ci struct signal_paths_entry *signal_paths_entry = NULL; 102153a5a1b3Sopenharmony_ci 102253a5a1b3Sopenharmony_ci pa_assert(p); 102353a5a1b3Sopenharmony_ci pa_assert(conn); 102453a5a1b3Sopenharmony_ci 102553a5a1b3Sopenharmony_ci pa_assert_se((conn_entry = pa_hashmap_get(p->connections, conn))); 102653a5a1b3Sopenharmony_ci 102753a5a1b3Sopenharmony_ci if (signal_name) { 102853a5a1b3Sopenharmony_ci if ((signal_paths_entry = pa_hashmap_remove(conn_entry->listening_signals, signal_name))) 102953a5a1b3Sopenharmony_ci signal_paths_entry_free(signal_paths_entry); 103053a5a1b3Sopenharmony_ci 103153a5a1b3Sopenharmony_ci } else { 103253a5a1b3Sopenharmony_ci conn_entry->listening_for_all_signals = false; 103353a5a1b3Sopenharmony_ci pa_idxset_remove_all(conn_entry->all_signals_objects, pa_xfree); 103453a5a1b3Sopenharmony_ci pa_hashmap_remove_all(conn_entry->listening_signals); 103553a5a1b3Sopenharmony_ci } 103653a5a1b3Sopenharmony_ci} 103753a5a1b3Sopenharmony_ci 103853a5a1b3Sopenharmony_civoid pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal_msg) { 103953a5a1b3Sopenharmony_ci struct connection_entry *conn_entry; 104053a5a1b3Sopenharmony_ci struct signal_paths_entry *signal_paths_entry; 104153a5a1b3Sopenharmony_ci void *state = NULL; 104253a5a1b3Sopenharmony_ci DBusMessage *signal_copy; 104353a5a1b3Sopenharmony_ci char *signal_string; 104453a5a1b3Sopenharmony_ci 104553a5a1b3Sopenharmony_ci pa_assert(p); 104653a5a1b3Sopenharmony_ci pa_assert(signal_msg); 104753a5a1b3Sopenharmony_ci pa_assert(dbus_message_get_type(signal_msg) == DBUS_MESSAGE_TYPE_SIGNAL); 104853a5a1b3Sopenharmony_ci pa_assert(dbus_message_get_path(signal_msg)); 104953a5a1b3Sopenharmony_ci pa_assert(dbus_message_get_interface(signal_msg)); 105053a5a1b3Sopenharmony_ci pa_assert(dbus_message_get_member(signal_msg)); 105153a5a1b3Sopenharmony_ci 105253a5a1b3Sopenharmony_ci signal_string = pa_sprintf_malloc("%s.%s", dbus_message_get_interface(signal_msg), dbus_message_get_member(signal_msg)); 105353a5a1b3Sopenharmony_ci 105453a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(conn_entry, p->connections, state) { 105553a5a1b3Sopenharmony_ci if ((conn_entry->listening_for_all_signals /* Case 1: listening for all signals */ 105653a5a1b3Sopenharmony_ci && (pa_idxset_get_by_data(conn_entry->all_signals_objects, dbus_message_get_path(signal_msg), NULL) 105753a5a1b3Sopenharmony_ci || pa_idxset_isempty(conn_entry->all_signals_objects))) 105853a5a1b3Sopenharmony_ci 105953a5a1b3Sopenharmony_ci || (!conn_entry->listening_for_all_signals /* Case 2: not listening for all signals */ 106053a5a1b3Sopenharmony_ci && (signal_paths_entry = pa_hashmap_get(conn_entry->listening_signals, signal_string)) 106153a5a1b3Sopenharmony_ci && (pa_idxset_get_by_data(signal_paths_entry->paths, dbus_message_get_path(signal_msg), NULL) 106253a5a1b3Sopenharmony_ci || pa_idxset_isempty(signal_paths_entry->paths)))) { 106353a5a1b3Sopenharmony_ci 106453a5a1b3Sopenharmony_ci pa_assert_se(signal_copy = dbus_message_copy(signal_msg)); 106553a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_send(conn_entry->connection, signal_copy, NULL)); 106653a5a1b3Sopenharmony_ci dbus_message_unref(signal_copy); 106753a5a1b3Sopenharmony_ci } 106853a5a1b3Sopenharmony_ci } 106953a5a1b3Sopenharmony_ci 107053a5a1b3Sopenharmony_ci pa_xfree(signal_string); 107153a5a1b3Sopenharmony_ci} 107253a5a1b3Sopenharmony_ci 107353a5a1b3Sopenharmony_ciconst char **pa_dbus_protocol_get_extensions(pa_dbus_protocol *p, unsigned *n) { 107453a5a1b3Sopenharmony_ci const char **extensions; 107553a5a1b3Sopenharmony_ci const char *ext_name; 107653a5a1b3Sopenharmony_ci void *state = NULL; 107753a5a1b3Sopenharmony_ci unsigned i = 0; 107853a5a1b3Sopenharmony_ci 107953a5a1b3Sopenharmony_ci pa_assert(p); 108053a5a1b3Sopenharmony_ci pa_assert(n); 108153a5a1b3Sopenharmony_ci 108253a5a1b3Sopenharmony_ci *n = pa_idxset_size(p->extensions); 108353a5a1b3Sopenharmony_ci 108453a5a1b3Sopenharmony_ci if (*n <= 0) 108553a5a1b3Sopenharmony_ci return NULL; 108653a5a1b3Sopenharmony_ci 108753a5a1b3Sopenharmony_ci extensions = pa_xnew(const char *, *n); 108853a5a1b3Sopenharmony_ci 108953a5a1b3Sopenharmony_ci while ((ext_name = pa_idxset_iterate(p->extensions, &state, NULL))) 109053a5a1b3Sopenharmony_ci extensions[i++] = ext_name; 109153a5a1b3Sopenharmony_ci 109253a5a1b3Sopenharmony_ci return extensions; 109353a5a1b3Sopenharmony_ci} 109453a5a1b3Sopenharmony_ci 109553a5a1b3Sopenharmony_ciint pa_dbus_protocol_register_extension(pa_dbus_protocol *p, const char *name) { 109653a5a1b3Sopenharmony_ci char *internal_name; 109753a5a1b3Sopenharmony_ci 109853a5a1b3Sopenharmony_ci pa_assert(p); 109953a5a1b3Sopenharmony_ci pa_assert(name); 110053a5a1b3Sopenharmony_ci 110153a5a1b3Sopenharmony_ci internal_name = pa_xstrdup(name); 110253a5a1b3Sopenharmony_ci 110353a5a1b3Sopenharmony_ci if (pa_idxset_put(p->extensions, internal_name, NULL) < 0) { 110453a5a1b3Sopenharmony_ci pa_xfree(internal_name); 110553a5a1b3Sopenharmony_ci return -1; 110653a5a1b3Sopenharmony_ci } 110753a5a1b3Sopenharmony_ci 110853a5a1b3Sopenharmony_ci pa_hook_fire(&p->hooks[PA_DBUS_PROTOCOL_HOOK_EXTENSION_REGISTERED], internal_name); 110953a5a1b3Sopenharmony_ci 111053a5a1b3Sopenharmony_ci return 0; 111153a5a1b3Sopenharmony_ci} 111253a5a1b3Sopenharmony_ci 111353a5a1b3Sopenharmony_ciint pa_dbus_protocol_unregister_extension(pa_dbus_protocol *p, const char *name) { 111453a5a1b3Sopenharmony_ci char *internal_name; 111553a5a1b3Sopenharmony_ci 111653a5a1b3Sopenharmony_ci pa_assert(p); 111753a5a1b3Sopenharmony_ci pa_assert(name); 111853a5a1b3Sopenharmony_ci 111953a5a1b3Sopenharmony_ci if (!(internal_name = pa_idxset_remove_by_data(p->extensions, name, NULL))) 112053a5a1b3Sopenharmony_ci return -1; 112153a5a1b3Sopenharmony_ci 112253a5a1b3Sopenharmony_ci pa_hook_fire(&p->hooks[PA_DBUS_PROTOCOL_HOOK_EXTENSION_UNREGISTERED], internal_name); 112353a5a1b3Sopenharmony_ci 112453a5a1b3Sopenharmony_ci pa_xfree(internal_name); 112553a5a1b3Sopenharmony_ci 112653a5a1b3Sopenharmony_ci return 0; 112753a5a1b3Sopenharmony_ci} 112853a5a1b3Sopenharmony_ci 112953a5a1b3Sopenharmony_cipa_hook_slot *pa_dbus_protocol_hook_connect( 113053a5a1b3Sopenharmony_ci pa_dbus_protocol *p, 113153a5a1b3Sopenharmony_ci pa_dbus_protocol_hook_t hook, 113253a5a1b3Sopenharmony_ci pa_hook_priority_t prio, 113353a5a1b3Sopenharmony_ci pa_hook_cb_t cb, 113453a5a1b3Sopenharmony_ci void *data) { 113553a5a1b3Sopenharmony_ci pa_assert(p); 113653a5a1b3Sopenharmony_ci pa_assert(hook < PA_DBUS_PROTOCOL_HOOK_MAX); 113753a5a1b3Sopenharmony_ci pa_assert(cb); 113853a5a1b3Sopenharmony_ci 113953a5a1b3Sopenharmony_ci return pa_hook_connect(&p->hooks[hook], prio, cb, data); 114053a5a1b3Sopenharmony_ci} 1141