LCOV - code coverage report
Current view: top level - pulsecore - protocol-dbus.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 0 520 0.0 %
Date: 2012-07-17 Functions: 0 36 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 484 0.0 %

           Branch data     Line data    Source code
       1                 :            : /***
       2                 :            :   This file is part of PulseAudio.
       3                 :            : 
       4                 :            :   Copyright 2009 Tanu Kaskinen
       5                 :            : 
       6                 :            :   PulseAudio is free software; you can redistribute it and/or modify
       7                 :            :   it under the terms of the GNU Lesser General Public License as published
       8                 :            :   by the Free Software Foundation; either version 2.1 of the License,
       9                 :            :   or (at your option) any later version.
      10                 :            : 
      11                 :            :   PulseAudio is distributed in the hope that it will be useful, but
      12                 :            :   WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      14                 :            :   General Public License for more details.
      15                 :            : 
      16                 :            :   You should have received a copy of the GNU Lesser General Public License
      17                 :            :   along with PulseAudio; if not, write to the Free Software
      18                 :            :   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
      19                 :            :   USA.
      20                 :            : ***/
      21                 :            : 
      22                 :            : #ifdef HAVE_CONFIG_H
      23                 :            : #include <config.h>
      24                 :            : #endif
      25                 :            : 
      26                 :            : #include <dbus/dbus.h>
      27                 :            : 
      28                 :            : #include <pulse/xmalloc.h>
      29                 :            : 
      30                 :            : #include <pulsecore/core-util.h>
      31                 :            : #include <pulsecore/dbus-util.h>
      32                 :            : #include <pulsecore/hashmap.h>
      33                 :            : #include <pulsecore/idxset.h>
      34                 :            : #include <pulsecore/shared.h>
      35                 :            : #include <pulsecore/strbuf.h>
      36                 :            : 
      37                 :            : #include "protocol-dbus.h"
      38                 :            : 
      39                 :            : struct pa_dbus_protocol {
      40                 :            :     PA_REFCNT_DECLARE;
      41                 :            : 
      42                 :            :     pa_core *core;
      43                 :            :     pa_hashmap *objects; /* Object path -> struct object_entry */
      44                 :            :     pa_hashmap *connections; /* DBusConnection -> struct connection_entry */
      45                 :            :     pa_idxset *extensions; /* Strings */
      46                 :            : 
      47                 :            :     pa_hook hooks[PA_DBUS_PROTOCOL_HOOK_MAX];
      48                 :            : };
      49                 :            : 
      50                 :            : struct object_entry {
      51                 :            :     char *path;
      52                 :            :     pa_hashmap *interfaces; /* Interface name -> struct interface_entry */
      53                 :            :     char *introspection;
      54                 :            : };
      55                 :            : 
      56                 :            : struct connection_entry {
      57                 :            :     DBusConnection *connection;
      58                 :            :     pa_client *client;
      59                 :            : 
      60                 :            :     pa_bool_t listening_for_all_signals;
      61                 :            : 
      62                 :            :     /* Contains object paths. If this is empty, then signals from all objects
      63                 :            :      * are accepted. Only used when listening_for_all_signals == TRUE. */
      64                 :            :     pa_idxset *all_signals_objects;
      65                 :            : 
      66                 :            :     /* Signal name -> signal paths entry. The entries contain object paths. If
      67                 :            :      * a path set is empty, then that signal is accepted from all objects. This
      68                 :            :      * variable is only used when listening_for_all_signals == FALSE. */
      69                 :            :     pa_hashmap *listening_signals;
      70                 :            : };
      71                 :            : 
      72                 :            : /* Only used in connection entries' listening_signals hashmap. */
      73                 :            : struct signal_paths_entry {
      74                 :            :     char *signal;
      75                 :            :     pa_idxset *paths;
      76                 :            : };
      77                 :            : 
      78                 :            : struct interface_entry {
      79                 :            :     char *name;
      80                 :            :     pa_hashmap *method_handlers;
      81                 :            :     pa_hashmap *method_signatures; /* Derived from method_handlers. Contains only "in" arguments. */
      82                 :            :     pa_hashmap *property_handlers;
      83                 :            :     pa_dbus_receive_cb_t get_all_properties_cb;
      84                 :            :     pa_dbus_signal_info *signals;
      85                 :            :     unsigned n_signals;
      86                 :            :     void *userdata;
      87                 :            : };
      88                 :            : 
      89                 :          0 : char *pa_get_dbus_address_from_server_type(pa_server_type_t server_type) {
      90                 :          0 :     char *address = NULL;
      91                 :          0 :     char *runtime_path = NULL;
      92                 :          0 :     char *escaped_path = NULL;
      93                 :            : 
      94   [ #  #  #  # ]:          0 :     switch (server_type) {
      95                 :            :         case PA_SERVER_TYPE_USER:
      96         [ #  # ]:          0 :             pa_assert_se((runtime_path = pa_runtime_path(PA_DBUS_SOCKET_NAME)));
      97         [ #  # ]:          0 :             pa_assert_se((escaped_path = dbus_address_escape_value(runtime_path)));
      98                 :          0 :             address = pa_sprintf_malloc("unix:path=%s", escaped_path);
      99                 :          0 :             break;
     100                 :            : 
     101                 :            :         case PA_SERVER_TYPE_SYSTEM:
     102         [ #  # ]:          0 :             pa_assert_se((escaped_path = dbus_address_escape_value(PA_DBUS_SYSTEM_SOCKET_PATH)));
     103                 :          0 :             address = pa_sprintf_malloc("unix:path=%s", escaped_path);
     104                 :          0 :             break;
     105                 :            : 
     106                 :            :         case PA_SERVER_TYPE_NONE:
     107                 :          0 :             address = pa_xnew0(char, 1);
     108                 :          0 :             break;
     109                 :            : 
     110                 :            :         default:
     111                 :          0 :             pa_assert_not_reached();
     112                 :            :     }
     113                 :            : 
     114                 :          0 :     pa_xfree(runtime_path);
     115                 :          0 :     dbus_free(escaped_path);
     116                 :            : 
     117                 :          0 :     return address;
     118                 :            : }
     119                 :            : 
     120                 :          0 : static pa_dbus_protocol *dbus_protocol_new(pa_core *c) {
     121                 :            :     pa_dbus_protocol *p;
     122                 :            :     unsigned i;
     123                 :            : 
     124         [ #  # ]:          0 :     pa_assert(c);
     125                 :            : 
     126                 :          0 :     p = pa_xnew(pa_dbus_protocol, 1);
     127                 :          0 :     PA_REFCNT_INIT(p);
     128                 :          0 :     p->core = c;
     129                 :          0 :     p->objects = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     130                 :          0 :     p->connections = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
     131                 :          0 :     p->extensions = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     132                 :            : 
     133         [ #  # ]:          0 :     for (i = 0; i < PA_DBUS_PROTOCOL_HOOK_MAX; ++i)
     134                 :          0 :         pa_hook_init(&p->hooks[i], p);
     135                 :            : 
     136         [ #  # ]:          0 :     pa_assert_se(pa_shared_set(c, "dbus-protocol", p) >= 0);
     137                 :            : 
     138                 :          0 :     return p;
     139                 :            : }
     140                 :            : 
     141                 :          0 : pa_dbus_protocol* pa_dbus_protocol_get(pa_core *c) {
     142                 :            :     pa_dbus_protocol *p;
     143                 :            : 
     144         [ #  # ]:          0 :     if ((p = pa_shared_get(c, "dbus-protocol")))
     145                 :          0 :         return pa_dbus_protocol_ref(p);
     146                 :            : 
     147                 :          0 :     return dbus_protocol_new(c);
     148                 :            : }
     149                 :            : 
     150                 :          0 : pa_dbus_protocol* pa_dbus_protocol_ref(pa_dbus_protocol *p) {
     151         [ #  # ]:          0 :     pa_assert(p);
     152         [ #  # ]:          0 :     pa_assert(PA_REFCNT_VALUE(p) >= 1);
     153                 :            : 
     154                 :          0 :     PA_REFCNT_INC(p);
     155                 :            : 
     156                 :          0 :     return p;
     157                 :            : }
     158                 :            : 
     159                 :          0 : void pa_dbus_protocol_unref(pa_dbus_protocol *p) {
     160                 :            :     unsigned i;
     161                 :            : 
     162         [ #  # ]:          0 :     pa_assert(p);
     163         [ #  # ]:          0 :     pa_assert(PA_REFCNT_VALUE(p) >= 1);
     164                 :            : 
     165         [ #  # ]:          0 :     if (PA_REFCNT_DEC(p) > 0)
     166                 :          0 :         return;
     167                 :            : 
     168         [ #  # ]:          0 :     pa_assert(pa_hashmap_isempty(p->objects));
     169         [ #  # ]:          0 :     pa_assert(pa_hashmap_isempty(p->connections));
     170         [ #  # ]:          0 :     pa_assert(pa_idxset_isempty(p->extensions));
     171                 :            : 
     172                 :          0 :     pa_hashmap_free(p->objects, NULL, NULL);
     173                 :          0 :     pa_hashmap_free(p->connections, NULL, NULL);
     174                 :          0 :     pa_idxset_free(p->extensions, NULL, NULL);
     175                 :            : 
     176         [ #  # ]:          0 :     for (i = 0; i < PA_DBUS_PROTOCOL_HOOK_MAX; ++i)
     177                 :          0 :         pa_hook_done(&p->hooks[i]);
     178                 :            : 
     179         [ #  # ]:          0 :     pa_assert_se(pa_shared_remove(p->core, "dbus-protocol") >= 0);
     180                 :            : 
     181                 :          0 :     pa_xfree(p);
     182                 :            : }
     183                 :            : 
     184                 :          0 : static void update_introspection(struct object_entry *oe) {
     185                 :            :     pa_strbuf *buf;
     186                 :          0 :     void *interfaces_state = NULL;
     187                 :          0 :     struct interface_entry *iface_entry = NULL;
     188                 :            : 
     189         [ #  # ]:          0 :     pa_assert(oe);
     190                 :            : 
     191                 :          0 :     buf = pa_strbuf_new();
     192                 :          0 :     pa_strbuf_puts(buf, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
     193                 :          0 :     pa_strbuf_puts(buf, "<node>\n");
     194                 :            : 
     195         [ #  # ]:          0 :     PA_HASHMAP_FOREACH(iface_entry, oe->interfaces, interfaces_state) {
     196                 :            :         pa_dbus_method_handler *method_handler;
     197                 :            :         pa_dbus_property_handler *property_handler;
     198                 :          0 :         void *handlers_state = NULL;
     199                 :            :         unsigned i;
     200                 :            :         unsigned j;
     201                 :            : 
     202                 :          0 :         pa_strbuf_printf(buf, " <interface name=\"%s\">\n", iface_entry->name);
     203                 :            : 
     204         [ #  # ]:          0 :         PA_HASHMAP_FOREACH(method_handler, iface_entry->method_handlers, handlers_state) {
     205                 :          0 :             pa_strbuf_printf(buf, "  <method name=\"%s\">\n", method_handler->method_name);
     206                 :            : 
     207         [ #  # ]:          0 :             for (i = 0; i < method_handler->n_arguments; ++i)
     208                 :          0 :                 pa_strbuf_printf(buf, "   <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
     209                 :          0 :                                  method_handler->arguments[i].name,
     210                 :          0 :                                  method_handler->arguments[i].type,
     211                 :          0 :                                  method_handler->arguments[i].direction);
     212                 :            : 
     213                 :          0 :             pa_strbuf_puts(buf, "  </method>\n");
     214                 :            :         }
     215                 :            : 
     216                 :          0 :         handlers_state = NULL;
     217                 :            : 
     218         [ #  # ]:          0 :         PA_HASHMAP_FOREACH(property_handler, iface_entry->property_handlers, handlers_state)
     219         [ #  # ]:          0 :             pa_strbuf_printf(buf, "  <property name=\"%s\" type=\"%s\" access=\"%s\"/>\n",
     220                 :            :                              property_handler->property_name,
     221                 :            :                              property_handler->type,
     222         [ #  # ]:          0 :                              property_handler->get_cb ? (property_handler->set_cb ? "readwrite" : "read") : "write");
     223                 :            : 
     224         [ #  # ]:          0 :         for (i = 0; i < iface_entry->n_signals; ++i) {
     225                 :          0 :             pa_strbuf_printf(buf, "  <signal name=\"%s\">\n", iface_entry->signals[i].name);
     226                 :            : 
     227         [ #  # ]:          0 :             for (j = 0; j < iface_entry->signals[i].n_arguments; ++j)
     228                 :          0 :                 pa_strbuf_printf(buf, "   <arg name=\"%s\" type=\"%s\"/>\n", iface_entry->signals[i].arguments[j].name,
     229                 :          0 :                                                                              iface_entry->signals[i].arguments[j].type);
     230                 :            : 
     231                 :          0 :             pa_strbuf_puts(buf, "  </signal>\n");
     232                 :            :         }
     233                 :            : 
     234                 :          0 :         pa_strbuf_puts(buf, " </interface>\n");
     235                 :            :     }
     236                 :            : 
     237                 :          0 :     pa_strbuf_puts(buf, " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"
     238                 :            :                         "  <method name=\"Introspect\">\n"
     239                 :            :                         "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
     240                 :            :                         "  </method>\n"
     241                 :            :                         " </interface>\n"
     242                 :            :                         " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n"
     243                 :            :                         "  <method name=\"Get\">\n"
     244                 :            :                         "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
     245                 :            :                         "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
     246                 :            :                         "   <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"
     247                 :            :                         "  </method>\n"
     248                 :            :                         "  <method name=\"Set\">\n"
     249                 :            :                         "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
     250                 :            :                         "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
     251                 :            :                         "   <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"
     252                 :            :                         "  </method>\n"
     253                 :            :                         "  <method name=\"GetAll\">\n"
     254                 :            :                         "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
     255                 :            :                         "   <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n"
     256                 :            :                         "  </method>\n"
     257                 :            :                         " </interface>\n");
     258                 :            : 
     259                 :          0 :     pa_strbuf_puts(buf, "</node>\n");
     260                 :            : 
     261                 :          0 :     pa_xfree(oe->introspection);
     262                 :          0 :     oe->introspection = pa_strbuf_tostring_free(buf);
     263                 :          0 : }
     264                 :            : 
     265                 :            : /* Return value of find_handler() and its subfunctions. */
     266                 :            : enum find_result_t {
     267                 :            :     /* The received message is a valid .Get call. */
     268                 :            :     FOUND_GET_PROPERTY,
     269                 :            : 
     270                 :            :     /* The received message is a valid .Set call. */
     271                 :            :     FOUND_SET_PROPERTY,
     272                 :            : 
     273                 :            :     /* The received message is a valid .GetAll call. */
     274                 :            :     FOUND_GET_ALL,
     275                 :            : 
     276                 :            :     /* The received message is a valid method call. */
     277                 :            :     FOUND_METHOD,
     278                 :            : 
     279                 :            :     /* The interface of the received message hasn't been registered for the
     280                 :            :      * destination object. */
     281                 :            :     NO_SUCH_INTERFACE,
     282                 :            : 
     283                 :            :     /* No property handler was found for the received .Get or .Set call. */
     284                 :            :     NO_SUCH_PROPERTY,
     285                 :            : 
     286                 :            :     /* The interface argument of a property call didn't match any registered
     287                 :            :      * interface. */
     288                 :            :     NO_SUCH_PROPERTY_INTERFACE,
     289                 :            : 
     290                 :            :     /* The received message called .Get or .Set for a property whose access
     291                 :            :      * mode doesn't match the call. */
     292                 :            :     PROPERTY_ACCESS_DENIED,
     293                 :            : 
     294                 :            :     /* The new value signature of a .Set call didn't match the expected
     295                 :            :      * signature. */
     296                 :            :     INVALID_PROPERTY_SIG,
     297                 :            : 
     298                 :            :     /* No method handler was found for the received message. */
     299                 :            :     NO_SUCH_METHOD,
     300                 :            : 
     301                 :            :     /* The signature of the received message didn't match the expected
     302                 :            :      * signature. Despite the name, this can also be returned for a property
     303                 :            :      * call if its message signature is invalid. */
     304                 :            :     INVALID_METHOD_SIG
     305                 :            : };
     306                 :            : 
     307                 :            : /* Data for resolving the correct reaction to a received message. */
     308                 :            : struct call_info {
     309                 :            :     DBusMessage *message; /* The received message. */
     310                 :            :     struct object_entry *obj_entry;
     311                 :            :     const char *interface; /* Destination interface name (extracted from the message). */
     312                 :            :     struct interface_entry *iface_entry;
     313                 :            : 
     314                 :            :     const char *property; /* Property name (extracted from the message). */
     315                 :            :     const char *property_interface; /* The interface argument of a property call is stored here. */
     316                 :            :     pa_dbus_property_handler *property_handler;
     317                 :            :     const char *expected_property_sig; /* Property signature from the introspection data. */
     318                 :            :     const char *property_sig; /* The signature of the new value in the received .Set message. */
     319                 :            :     DBusMessageIter variant_iter; /* Iterator pointing to the beginning of the new value variant of a .Set call. */
     320                 :            : 
     321                 :            :     const char *method; /* Method name (extracted from the message). */
     322                 :            :     pa_dbus_method_handler *method_handler;
     323                 :            :     const char *expected_method_sig; /* Method signature from the introspection data. */
     324                 :            :     const char *method_sig; /* The signature of the received message. */
     325                 :            : };
     326                 :            : 
     327                 :            : /* Called when call_info->property has been set and the property interface has
     328                 :            :  * not been given. In case of a Set call, call_info->property_sig is also set,
     329                 :            :  * which is checked against the expected value in this function. */
     330                 :          0 : static enum find_result_t find_handler_by_property(struct call_info *call_info) {
     331                 :          0 :     void *state = NULL;
     332                 :            : 
     333         [ #  # ]:          0 :     pa_assert(call_info);
     334                 :            : 
     335         [ #  # ]:          0 :     PA_HASHMAP_FOREACH(call_info->iface_entry, call_info->obj_entry->interfaces, state) {
     336         [ #  # ]:          0 :         if ((call_info->property_handler = pa_hashmap_get(call_info->iface_entry->property_handlers, call_info->property))) {
     337 [ #  # ][ #  # ]:          0 :             if (pa_streq(call_info->method, "Get"))
         [ #  # ][ #  # ]
     338         [ #  # ]:          0 :                 return call_info->property_handler->get_cb ? FOUND_GET_PROPERTY : PROPERTY_ACCESS_DENIED;
     339                 :            : 
     340 [ #  # ][ #  # ]:          0 :             else if (pa_streq(call_info->method, "Set")) {
         [ #  # ][ #  # ]
     341                 :          0 :                 call_info->expected_property_sig = call_info->property_handler->type;
     342                 :            : 
     343         [ #  # ]:          0 :                 if (pa_streq(call_info->property_sig, call_info->expected_property_sig))
     344         [ #  # ]:          0 :                     return call_info->property_handler->set_cb ? FOUND_SET_PROPERTY : PROPERTY_ACCESS_DENIED;
     345                 :            :                 else
     346                 :            :                     return INVALID_PROPERTY_SIG;
     347                 :            : 
     348                 :            :             } else
     349                 :          0 :                 pa_assert_not_reached();
     350                 :            :         }
     351                 :            :     }
     352                 :            : 
     353                 :            :     return NO_SUCH_PROPERTY;
     354                 :            : }
     355                 :            : 
     356                 :          0 : static enum find_result_t find_handler_by_method(struct call_info *call_info) {
     357                 :          0 :     void *state = NULL;
     358                 :            : 
     359         [ #  # ]:          0 :     pa_assert(call_info);
     360                 :            : 
     361         [ #  # ]:          0 :     PA_HASHMAP_FOREACH(call_info->iface_entry, call_info->obj_entry->interfaces, state) {
     362         [ #  # ]:          0 :         if ((call_info->method_handler = pa_hashmap_get(call_info->iface_entry->method_handlers, call_info->method))) {
     363         [ #  # ]:          0 :             pa_assert_se(call_info->expected_method_sig = pa_hashmap_get(call_info->iface_entry->method_signatures, call_info->method));
     364                 :            : 
     365         [ #  # ]:          0 :             if (pa_streq(call_info->method_sig, call_info->expected_method_sig))
     366                 :            :                 return FOUND_METHOD;
     367                 :            :             else
     368                 :          0 :                 return INVALID_METHOD_SIG;
     369                 :            :         }
     370                 :            :     }
     371                 :            : 
     372                 :            :     return NO_SUCH_METHOD;
     373                 :            : }
     374                 :            : 
     375                 :          0 : static enum find_result_t find_handler_from_properties_call(struct call_info *call_info) {
     376         [ #  # ]:          0 :     pa_assert(call_info);
     377                 :            : 
     378         [ #  # ]:          0 :     if (pa_streq(call_info->method, "GetAll")) {
     379                 :          0 :         call_info->expected_method_sig = "s";
     380         [ #  # ]:          0 :         if (!pa_streq(call_info->method_sig, call_info->expected_method_sig))
     381                 :            :             return INVALID_METHOD_SIG;
     382                 :            : 
     383         [ #  # ]:          0 :         pa_assert_se(dbus_message_get_args(call_info->message, NULL,
     384                 :            :                                            DBUS_TYPE_STRING, &call_info->property_interface,
     385                 :            :                                            DBUS_TYPE_INVALID));
     386                 :            : 
     387         [ #  # ]:          0 :         if (*call_info->property_interface) {
     388         [ #  # ]:          0 :             if ((call_info->iface_entry = pa_hashmap_get(call_info->obj_entry->interfaces, call_info->property_interface)))
     389                 :            :                 return FOUND_GET_ALL;
     390                 :            :             else
     391                 :          0 :                 return NO_SUCH_PROPERTY_INTERFACE;
     392                 :            : 
     393                 :            :         } else {
     394         [ #  # ]:          0 :             pa_assert_se(call_info->iface_entry = pa_hashmap_first(call_info->obj_entry->interfaces));
     395                 :            :             return FOUND_GET_ALL;
     396                 :            :         }
     397                 :            : 
     398 [ #  # ][ #  # ]:          0 :     } else if (pa_streq(call_info->method, "Get")) {
         [ #  # ][ #  # ]
     399                 :          0 :         call_info->expected_method_sig = "ss";
     400         [ #  # ]:          0 :         if (!pa_streq(call_info->method_sig, call_info->expected_method_sig))
     401                 :            :             return INVALID_METHOD_SIG;
     402                 :            : 
     403         [ #  # ]:          0 :         pa_assert_se(dbus_message_get_args(call_info->message, NULL,
     404                 :            :                                            DBUS_TYPE_STRING, &call_info->property_interface,
     405                 :            :                                            DBUS_TYPE_STRING, &call_info->property,
     406                 :            :                                            DBUS_TYPE_INVALID));
     407                 :            : 
     408         [ #  # ]:          0 :         if (*call_info->property_interface) {
     409         [ #  # ]:          0 :             if (!(call_info->iface_entry = pa_hashmap_get(call_info->obj_entry->interfaces, call_info->property_interface)))
     410                 :            :                 return NO_SUCH_PROPERTY_INTERFACE;
     411         [ #  # ]:          0 :             else if ((call_info->property_handler =
     412                 :          0 :                         pa_hashmap_get(call_info->iface_entry->property_handlers, call_info->property)))
     413         [ #  # ]:          0 :                 return call_info->property_handler->get_cb ? FOUND_GET_PROPERTY : PROPERTY_ACCESS_DENIED;
     414                 :            :             else
     415                 :            :                 return NO_SUCH_PROPERTY;
     416                 :            : 
     417                 :            :         } else
     418                 :          0 :             return find_handler_by_property(call_info);
     419                 :            : 
     420 [ #  # ][ #  # ]:          0 :     } else if (pa_streq(call_info->method, "Set")) {
         [ #  # ][ #  # ]
     421                 :            :         DBusMessageIter msg_iter;
     422                 :            : 
     423                 :          0 :         call_info->expected_method_sig = "ssv";
     424         [ #  # ]:          0 :         if (!pa_streq(call_info->method_sig, call_info->expected_method_sig))
     425                 :            :             return INVALID_METHOD_SIG;
     426                 :            : 
     427         [ #  # ]:          0 :         pa_assert_se(dbus_message_iter_init(call_info->message, &msg_iter));
     428                 :            : 
     429                 :          0 :         dbus_message_iter_get_basic(&msg_iter, &call_info->property_interface);
     430         [ #  # ]:          0 :         pa_assert_se(dbus_message_iter_next(&msg_iter));
     431                 :          0 :         dbus_message_iter_get_basic(&msg_iter, &call_info->property);
     432         [ #  # ]:          0 :         pa_assert_se(dbus_message_iter_next(&msg_iter));
     433                 :            : 
     434                 :          0 :         dbus_message_iter_recurse(&msg_iter, &call_info->variant_iter);
     435                 :            : 
     436                 :          0 :         call_info->property_sig = dbus_message_iter_get_signature(&call_info->variant_iter);
     437                 :            : 
     438         [ #  # ]:          0 :         if (*call_info->property_interface) {
     439         [ #  # ]:          0 :             if (!(call_info->iface_entry = pa_hashmap_get(call_info->obj_entry->interfaces, call_info->property_interface)))
     440                 :            :                 return NO_SUCH_PROPERTY_INTERFACE;
     441                 :            : 
     442         [ #  # ]:          0 :             else if ((call_info->property_handler =
     443                 :          0 :                         pa_hashmap_get(call_info->iface_entry->property_handlers, call_info->property))) {
     444                 :          0 :                 call_info->expected_property_sig = call_info->property_handler->type;
     445                 :            : 
     446         [ #  # ]:          0 :                 if (pa_streq(call_info->property_sig, call_info->expected_property_sig))
     447         [ #  # ]:          0 :                     return call_info->property_handler->set_cb ? FOUND_SET_PROPERTY : PROPERTY_ACCESS_DENIED;
     448                 :            :                 else
     449                 :            :                     return INVALID_PROPERTY_SIG;
     450                 :            : 
     451                 :            :             } else
     452                 :            :                 return NO_SUCH_PROPERTY;
     453                 :            : 
     454                 :            :         } else
     455                 :          0 :             return find_handler_by_property(call_info);
     456                 :            : 
     457                 :            :     } else
     458                 :          0 :         pa_assert_not_reached();
     459                 :            : }
     460                 :            : 
     461                 :          0 : static enum find_result_t find_handler(struct call_info *call_info) {
     462         [ #  # ]:          0 :     pa_assert(call_info);
     463                 :            : 
     464         [ #  # ]:          0 :     if (call_info->interface) {
     465         [ #  # ]:          0 :         if (pa_streq(call_info->interface, DBUS_INTERFACE_PROPERTIES))
     466                 :          0 :             return find_handler_from_properties_call(call_info);
     467                 :            : 
     468         [ #  # ]:          0 :         else if (!(call_info->iface_entry = pa_hashmap_get(call_info->obj_entry->interfaces, call_info->interface)))
     469                 :            :             return NO_SUCH_INTERFACE;
     470                 :            : 
     471         [ #  # ]:          0 :         else if ((call_info->method_handler = pa_hashmap_get(call_info->iface_entry->method_handlers, call_info->method))) {
     472         [ #  # ]:          0 :             pa_assert_se(call_info->expected_method_sig = pa_hashmap_get(call_info->iface_entry->method_signatures, call_info->method));
     473                 :            : 
     474         [ #  # ]:          0 :             if (!pa_streq(call_info->method_sig, call_info->expected_method_sig))
     475                 :            :                 return INVALID_METHOD_SIG;
     476                 :            : 
     477                 :          0 :             return FOUND_METHOD;
     478                 :            : 
     479                 :            :         } else
     480                 :            :             return NO_SUCH_METHOD;
     481                 :            : 
     482                 :            :     } else { /* The method call doesn't contain an interface. */
     483 [ #  # ][ #  # ]:          0 :         if (pa_streq(call_info->method, "Get") || pa_streq(call_info->method, "Set") || pa_streq(call_info->method, "GetAll")) {
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     484         [ #  # ]:          0 :             if (find_handler_by_method(call_info) == FOUND_METHOD)
     485                 :            :                 /* The object has a method named Get, Set or GetAll in some other interface than .Properties. */
     486                 :            :                 return FOUND_METHOD;
     487                 :            :             else
     488                 :            :                 /* Assume this is a .Properties call. */
     489                 :          0 :                 return find_handler_from_properties_call(call_info);
     490                 :            : 
     491                 :            :         } else /* This is not a .Properties call. */
     492                 :          0 :             return find_handler_by_method(call_info);
     493                 :            :     }
     494                 :            : }
     495                 :            : 
     496                 :          0 : static DBusHandlerResult handle_message_cb(DBusConnection *connection, DBusMessage *message, void *user_data) {
     497                 :          0 :     pa_dbus_protocol *p = user_data;
     498                 :            :     struct call_info call_info;
     499                 :            : 
     500         [ #  # ]:          0 :     pa_assert(connection);
     501         [ #  # ]:          0 :     pa_assert(message);
     502         [ #  # ]:          0 :     pa_assert(p);
     503         [ #  # ]:          0 :     pa_assert(p->objects);
     504                 :            : 
     505         [ #  # ]:          0 :     if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
     506                 :            :         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     507                 :            : 
     508                 :          0 :     pa_log_debug("Received message: destination = %s, interface = %s, member = %s",
     509                 :            :                  dbus_message_get_path(message),
     510                 :            :                  dbus_message_get_interface(message),
     511                 :            :                  dbus_message_get_member(message));
     512                 :            : 
     513                 :          0 :     call_info.message = message;
     514         [ #  # ]:          0 :     pa_assert_se(call_info.obj_entry = pa_hashmap_get(p->objects, dbus_message_get_path(message)));
     515                 :          0 :     call_info.interface = dbus_message_get_interface(message);
     516         [ #  # ]:          0 :     pa_assert_se(call_info.method = dbus_message_get_member(message));
     517         [ #  # ]:          0 :     pa_assert_se(call_info.method_sig = dbus_message_get_signature(message));
     518                 :            : 
     519   [ #  #  #  # ]:          0 :     if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") ||
     520         [ #  # ]:          0 :         (!dbus_message_get_interface(message) && dbus_message_has_member(message, "Introspect"))) {
     521                 :          0 :         pa_dbus_send_basic_value_reply(connection, message, DBUS_TYPE_STRING, &call_info.obj_entry->introspection);
     522                 :          0 :         goto finish;
     523                 :            :     }
     524                 :            : 
     525   [ #  #  #  #  :          0 :     switch (find_handler(&call_info)) {
          #  #  #  #  #  
                #  #  # ]
     526                 :            :         case FOUND_GET_PROPERTY:
     527                 :          0 :             call_info.property_handler->get_cb(connection, message, call_info.iface_entry->userdata);
     528                 :          0 :             break;
     529                 :            : 
     530                 :            :         case FOUND_SET_PROPERTY:
     531                 :          0 :             call_info.property_handler->set_cb(connection, message, &call_info.variant_iter, call_info.iface_entry->userdata);
     532                 :          0 :             break;
     533                 :            : 
     534                 :            :         case FOUND_METHOD:
     535                 :          0 :             call_info.method_handler->receive_cb(connection, message, call_info.iface_entry->userdata);
     536                 :          0 :             break;
     537                 :            : 
     538                 :            :         case FOUND_GET_ALL:
     539         [ #  # ]:          0 :             if (call_info.iface_entry->get_all_properties_cb)
     540                 :          0 :                 call_info.iface_entry->get_all_properties_cb(connection, message, call_info.iface_entry->userdata);
     541                 :            :             else {
     542                 :          0 :                 DBusMessage *dummy_reply = NULL;
     543                 :            :                 DBusMessageIter msg_iter;
     544                 :            :                 DBusMessageIter dict_iter;
     545                 :            : 
     546         [ #  # ]:          0 :                 pa_assert_se(dummy_reply = dbus_message_new_method_return(message));
     547                 :          0 :                 dbus_message_iter_init_append(dummy_reply, &msg_iter);
     548         [ #  # ]:          0 :                 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
     549         [ #  # ]:          0 :                 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
     550         [ #  # ]:          0 :                 pa_assert_se(dbus_connection_send(connection, dummy_reply, NULL));
     551                 :          0 :                 dbus_message_unref(dummy_reply);
     552                 :            :             }
     553                 :            :             break;
     554                 :            : 
     555                 :            :         case PROPERTY_ACCESS_DENIED:
     556                 :          0 :             pa_dbus_send_error(connection, message, DBUS_ERROR_ACCESS_DENIED,
     557                 :            :                                "%s access denied for property %s", call_info.method, call_info.property);
     558                 :          0 :             break;
     559                 :            : 
     560                 :            :         case NO_SUCH_METHOD:
     561                 :          0 :             pa_dbus_send_error(connection, message, DBUS_ERROR_UNKNOWN_METHOD, "No such method: %s", call_info.method);
     562                 :          0 :             break;
     563                 :            : 
     564                 :            :         case NO_SUCH_INTERFACE:
     565                 :          0 :             pa_dbus_send_error(connection, message, PA_DBUS_ERROR_NO_SUCH_INTERFACE, "No such interface: %s", call_info.interface);
     566                 :          0 :             break;
     567                 :            : 
     568                 :            :         case NO_SUCH_PROPERTY:
     569                 :          0 :             pa_dbus_send_error(connection, message, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "No such property: %s", call_info.property);
     570                 :          0 :             break;
     571                 :            : 
     572                 :            :         case NO_SUCH_PROPERTY_INTERFACE:
     573                 :          0 :             pa_dbus_send_error(connection, message, PA_DBUS_ERROR_NO_SUCH_INTERFACE, "No such property interface: %s", call_info.property_interface);
     574                 :          0 :             break;
     575                 :            : 
     576                 :            :         case INVALID_METHOD_SIG:
     577                 :          0 :             pa_dbus_send_error(connection, message, DBUS_ERROR_INVALID_ARGS,
     578                 :            :                                "Invalid signature for method %s: '%s'. Expected '%s'.",
     579                 :            :                                call_info.method, call_info.method_sig, call_info.expected_method_sig);
     580                 :          0 :             break;
     581                 :            : 
     582                 :            :         case INVALID_PROPERTY_SIG:
     583                 :          0 :             pa_dbus_send_error(connection, message, DBUS_ERROR_INVALID_ARGS,
     584                 :            :                                "Invalid signature for property %s: '%s'. Expected '%s'.",
     585                 :            :                                call_info.property, call_info.property_sig, call_info.expected_property_sig);
     586                 :          0 :             break;
     587                 :            : 
     588                 :            :         default:
     589                 :          0 :             pa_assert_not_reached();
     590                 :            :     }
     591                 :            : 
     592                 :            : finish:
     593                 :            :     return DBUS_HANDLER_RESULT_HANDLED;
     594                 :            : }
     595                 :            : 
     596                 :            : static DBusObjectPathVTable vtable = {
     597                 :            :     .unregister_function = NULL,
     598                 :            :     .message_function = handle_message_cb,
     599                 :            :     .dbus_internal_pad1 = NULL,
     600                 :            :     .dbus_internal_pad2 = NULL,
     601                 :            :     .dbus_internal_pad3 = NULL,
     602                 :            :     .dbus_internal_pad4 = NULL
     603                 :            : };
     604                 :            : 
     605                 :          0 : static void register_object(pa_dbus_protocol *p, struct object_entry *obj_entry) {
     606                 :            :     struct connection_entry *conn_entry;
     607                 :          0 :     void *state = NULL;
     608                 :            : 
     609         [ #  # ]:          0 :     pa_assert(p);
     610         [ #  # ]:          0 :     pa_assert(obj_entry);
     611                 :            : 
     612         [ #  # ]:          0 :     PA_HASHMAP_FOREACH(conn_entry, p->connections, state)
     613         [ #  # ]:          0 :         pa_assert_se(dbus_connection_register_object_path(conn_entry->connection, obj_entry->path, &vtable, p));
     614                 :          0 : }
     615                 :            : 
     616                 :          0 : static pa_dbus_arg_info *copy_args(const pa_dbus_arg_info *src, unsigned n) {
     617                 :            :     pa_dbus_arg_info *dst;
     618                 :            :     unsigned i;
     619                 :            : 
     620         [ #  # ]:          0 :     if (n == 0)
     621                 :            :         return NULL;
     622                 :            : 
     623         [ #  # ]:          0 :     pa_assert(src);
     624                 :            : 
     625                 :          0 :     dst = pa_xnew0(pa_dbus_arg_info, n);
     626                 :            : 
     627         [ #  # ]:          0 :     for (i = 0; i < n; ++i) {
     628                 :          0 :         dst[i].name = pa_xstrdup(src[i].name);
     629                 :          0 :         dst[i].type = pa_xstrdup(src[i].type);
     630                 :          0 :         dst[i].direction = pa_xstrdup(src[i].direction);
     631                 :            :     }
     632                 :            : 
     633                 :            :     return dst;
     634                 :            : }
     635                 :            : 
     636                 :          0 : static pa_hashmap *create_method_handlers(const pa_dbus_interface_info *info) {
     637                 :            :     pa_hashmap *handlers;
     638                 :            :     unsigned i;
     639                 :            : 
     640         [ #  # ]:          0 :     pa_assert(info);
     641 [ #  # ][ #  # ]:          0 :     pa_assert(info->method_handlers || info->n_method_handlers == 0);
     642                 :            : 
     643                 :          0 :     handlers = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     644                 :            : 
     645         [ #  # ]:          0 :     for (i = 0; i < info->n_method_handlers; ++i) {
     646                 :          0 :         pa_dbus_method_handler *h = pa_xnew(pa_dbus_method_handler, 1);
     647                 :          0 :         h->method_name = pa_xstrdup(info->method_handlers[i].method_name);
     648                 :          0 :         h->arguments = copy_args(info->method_handlers[i].arguments, info->method_handlers[i].n_arguments);
     649                 :          0 :         h->n_arguments = info->method_handlers[i].n_arguments;
     650                 :          0 :         h->receive_cb = info->method_handlers[i].receive_cb;
     651                 :            : 
     652                 :          0 :         pa_hashmap_put(handlers, h->method_name, h);
     653                 :            :     }
     654                 :            : 
     655                 :          0 :     return handlers;
     656                 :            : }
     657                 :            : 
     658                 :          0 : static pa_hashmap *extract_method_signatures(pa_hashmap *method_handlers) {
     659                 :          0 :     pa_hashmap *signatures = NULL;
     660                 :          0 :     pa_dbus_method_handler *handler = NULL;
     661                 :          0 :     void *state = NULL;
     662                 :          0 :     pa_strbuf *sig_buf = NULL;
     663                 :          0 :     unsigned i = 0;
     664                 :            : 
     665         [ #  # ]:          0 :     pa_assert(method_handlers);
     666                 :            : 
     667                 :          0 :     signatures = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     668                 :            : 
     669         [ #  # ]:          0 :     PA_HASHMAP_FOREACH(handler, method_handlers, state) {
     670                 :          0 :         sig_buf = pa_strbuf_new();
     671                 :            : 
     672         [ #  # ]:          0 :         for (i = 0; i < handler->n_arguments; ++i) {
     673 [ #  # ][ #  # ]:          0 :             if (pa_streq(handler->arguments[i].direction, "in"))
                 [ #  # ]
     674                 :          0 :                 pa_strbuf_puts(sig_buf, handler->arguments[i].type);
     675                 :            :         }
     676                 :            : 
     677                 :          0 :         pa_hashmap_put(signatures, handler->method_name, pa_strbuf_tostring_free(sig_buf));
     678                 :            :     }
     679                 :            : 
     680                 :          0 :     return signatures;
     681                 :            : }
     682                 :            : 
     683                 :          0 : static pa_hashmap *create_property_handlers(const pa_dbus_interface_info *info) {
     684                 :            :     pa_hashmap *handlers;
     685                 :          0 :     unsigned i = 0;
     686                 :            : 
     687         [ #  # ]:          0 :     pa_assert(info);
     688 [ #  # ][ #  # ]:          0 :     pa_assert(info->property_handlers || info->n_property_handlers == 0);
     689                 :            : 
     690                 :          0 :     handlers = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     691                 :            : 
     692         [ #  # ]:          0 :     for (i = 0; i < info->n_property_handlers; ++i) {
     693                 :          0 :         pa_dbus_property_handler *h = pa_xnew(pa_dbus_property_handler, 1);
     694                 :          0 :         h->property_name = pa_xstrdup(info->property_handlers[i].property_name);
     695                 :          0 :         h->type = pa_xstrdup(info->property_handlers[i].type);
     696                 :          0 :         h->get_cb = info->property_handlers[i].get_cb;
     697                 :          0 :         h->set_cb = info->property_handlers[i].set_cb;
     698                 :            : 
     699                 :          0 :         pa_hashmap_put(handlers, h->property_name, h);
     700                 :            :     }
     701                 :            : 
     702                 :          0 :     return handlers;
     703                 :            : }
     704                 :            : 
     705                 :          0 : static pa_dbus_signal_info *copy_signals(const pa_dbus_interface_info *info) {
     706                 :            :     pa_dbus_signal_info *dst;
     707                 :            :     unsigned i;
     708                 :            : 
     709         [ #  # ]:          0 :     pa_assert(info);
     710                 :            : 
     711         [ #  # ]:          0 :     if (info->n_signals == 0)
     712                 :            :         return NULL;
     713                 :            : 
     714         [ #  # ]:          0 :     pa_assert(info->signals);
     715                 :            : 
     716                 :          0 :     dst = pa_xnew(pa_dbus_signal_info, info->n_signals);
     717                 :            : 
     718         [ #  # ]:          0 :     for (i = 0; i < info->n_signals; ++i) {
     719                 :          0 :         dst[i].name = pa_xstrdup(info->signals[i].name);
     720                 :          0 :         dst[i].arguments = copy_args(info->signals[i].arguments, info->signals[i].n_arguments);
     721                 :          0 :         dst[i].n_arguments = info->signals[i].n_arguments;
     722                 :            :     }
     723                 :            : 
     724                 :            :     return dst;
     725                 :            : }
     726                 :            : 
     727                 :          0 : int pa_dbus_protocol_add_interface(pa_dbus_protocol *p,
     728                 :            :                                    const char *path,
     729                 :            :                                    const pa_dbus_interface_info *info,
     730                 :            :                                    void *userdata) {
     731                 :            :     struct object_entry *obj_entry;
     732                 :            :     struct interface_entry *iface_entry;
     733                 :          0 :     pa_bool_t obj_entry_created = FALSE;
     734                 :            : 
     735         [ #  # ]:          0 :     pa_assert(p);
     736         [ #  # ]:          0 :     pa_assert(path);
     737         [ #  # ]:          0 :     pa_assert(info);
     738         [ #  # ]:          0 :     pa_assert(info->name);
     739 [ #  # ][ #  # ]:          0 :     pa_assert(info->method_handlers || info->n_method_handlers == 0);
     740 [ #  # ][ #  # ]:          0 :     pa_assert(info->property_handlers || info->n_property_handlers == 0);
     741 [ #  # ][ #  # ]:          0 :     pa_assert(info->get_all_properties_cb || info->n_property_handlers == 0);
     742 [ #  # ][ #  # ]:          0 :     pa_assert(info->signals || info->n_signals == 0);
     743                 :            : 
     744         [ #  # ]:          0 :     if (!(obj_entry = pa_hashmap_get(p->objects, path))) {
     745                 :          0 :         obj_entry = pa_xnew(struct object_entry, 1);
     746                 :          0 :         obj_entry->path = pa_xstrdup(path);
     747                 :          0 :         obj_entry->interfaces = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     748                 :          0 :         obj_entry->introspection = NULL;
     749                 :            : 
     750                 :          0 :         pa_hashmap_put(p->objects, obj_entry->path, obj_entry);
     751                 :          0 :         obj_entry_created = TRUE;
     752                 :            :     }
     753                 :            : 
     754         [ #  # ]:          0 :     if (pa_hashmap_get(obj_entry->interfaces, info->name) != NULL)
     755                 :            :         goto fail; /* The interface was already registered. */
     756                 :            : 
     757                 :          0 :     iface_entry = pa_xnew(struct interface_entry, 1);
     758                 :          0 :     iface_entry->name = pa_xstrdup(info->name);
     759                 :          0 :     iface_entry->method_handlers = create_method_handlers(info);
     760                 :          0 :     iface_entry->method_signatures = extract_method_signatures(iface_entry->method_handlers);
     761                 :          0 :     iface_entry->property_handlers = create_property_handlers(info);
     762                 :          0 :     iface_entry->get_all_properties_cb = info->get_all_properties_cb;
     763                 :          0 :     iface_entry->signals = copy_signals(info);
     764                 :          0 :     iface_entry->n_signals = info->n_signals;
     765                 :          0 :     iface_entry->userdata = userdata;
     766                 :          0 :     pa_hashmap_put(obj_entry->interfaces, iface_entry->name, iface_entry);
     767                 :            : 
     768                 :          0 :     update_introspection(obj_entry);
     769                 :            : 
     770         [ #  # ]:          0 :     if (obj_entry_created)
     771                 :          0 :         register_object(p, obj_entry);
     772                 :            : 
     773                 :          0 :     pa_log_debug("Interface %s added for object %s", iface_entry->name, obj_entry->path);
     774                 :            : 
     775                 :          0 :     return 0;
     776                 :            : 
     777                 :            : fail:
     778                 :            :     return -1;
     779                 :            : }
     780                 :            : 
     781                 :          0 : static void unregister_object(pa_dbus_protocol *p, struct object_entry *obj_entry) {
     782                 :            :     struct connection_entry *conn_entry;
     783                 :          0 :     void *state = NULL;
     784                 :            : 
     785         [ #  # ]:          0 :     pa_assert(p);
     786         [ #  # ]:          0 :     pa_assert(obj_entry);
     787                 :            : 
     788         [ #  # ]:          0 :     PA_HASHMAP_FOREACH(conn_entry, p->connections, state)
     789         [ #  # ]:          0 :         pa_assert_se(dbus_connection_unregister_object_path(conn_entry->connection, obj_entry->path));
     790                 :          0 : }
     791                 :            : 
     792                 :          0 : static void method_handler_free_cb(void *p, void *userdata) {
     793                 :          0 :     pa_dbus_method_handler *h = p;
     794                 :            :     unsigned i;
     795                 :            : 
     796         [ #  # ]:          0 :     pa_assert(h);
     797                 :            : 
     798                 :          0 :     pa_xfree((char *) h->method_name);
     799                 :            : 
     800         [ #  # ]:          0 :     for (i = 0; i < h->n_arguments; ++i) {
     801                 :          0 :         pa_xfree((char *) h->arguments[i].name);
     802                 :          0 :         pa_xfree((char *) h->arguments[i].type);
     803                 :          0 :         pa_xfree((char *) h->arguments[i].direction);
     804                 :            :     }
     805                 :            : 
     806                 :          0 :     pa_xfree((pa_dbus_arg_info *) h->arguments);
     807                 :          0 :     pa_xfree(h);
     808                 :          0 : }
     809                 :            : 
     810                 :          0 : static void method_signature_free_cb(void *p, void *userdata) {
     811         [ #  # ]:          0 :     pa_assert(p);
     812                 :            : 
     813                 :          0 :     pa_xfree(p);
     814                 :          0 : }
     815                 :            : 
     816                 :          0 : static void property_handler_free_cb(void *p, void *userdata) {
     817                 :          0 :     pa_dbus_property_handler *h = p;
     818                 :            : 
     819         [ #  # ]:          0 :     pa_assert(h);
     820                 :            : 
     821                 :          0 :     pa_xfree((char *) h->property_name);
     822                 :          0 :     pa_xfree((char *) h->type);
     823                 :            : 
     824                 :          0 :     pa_xfree(h);
     825                 :          0 : }
     826                 :            : 
     827                 :          0 : int pa_dbus_protocol_remove_interface(pa_dbus_protocol *p, const char* path, const char* interface) {
     828                 :            :     struct object_entry *obj_entry;
     829                 :            :     struct interface_entry *iface_entry;
     830                 :            :     unsigned i;
     831                 :            : 
     832         [ #  # ]:          0 :     pa_assert(p);
     833         [ #  # ]:          0 :     pa_assert(path);
     834         [ #  # ]:          0 :     pa_assert(interface);
     835                 :            : 
     836         [ #  # ]:          0 :     if (!(obj_entry = pa_hashmap_get(p->objects, path)))
     837                 :            :         return -1;
     838                 :            : 
     839         [ #  # ]:          0 :     if (!(iface_entry = pa_hashmap_remove(obj_entry->interfaces, interface)))
     840                 :            :         return -1;
     841                 :            : 
     842                 :          0 :     update_introspection(obj_entry);
     843                 :            : 
     844                 :          0 :     pa_log_debug("Interface %s removed from object %s", iface_entry->name, obj_entry->path);
     845                 :            : 
     846                 :          0 :     pa_xfree(iface_entry->name);
     847                 :          0 :     pa_hashmap_free(iface_entry->method_signatures, method_signature_free_cb, NULL);
     848                 :          0 :     pa_hashmap_free(iface_entry->method_handlers, method_handler_free_cb, NULL);
     849                 :          0 :     pa_hashmap_free(iface_entry->property_handlers, property_handler_free_cb, NULL);
     850                 :            : 
     851         [ #  # ]:          0 :     for (i = 0; i < iface_entry->n_signals; ++i) {
     852                 :            :         unsigned j;
     853                 :            : 
     854                 :          0 :         pa_xfree((char *) iface_entry->signals[i].name);
     855                 :            : 
     856         [ #  # ]:          0 :         for (j = 0; j < iface_entry->signals[i].n_arguments; ++j) {
     857                 :          0 :             pa_xfree((char *) iface_entry->signals[i].arguments[j].name);
     858                 :          0 :             pa_xfree((char *) iface_entry->signals[i].arguments[j].type);
     859         [ #  # ]:          0 :             pa_assert(iface_entry->signals[i].arguments[j].direction == NULL);
     860                 :            :         }
     861                 :            : 
     862                 :          0 :         pa_xfree((pa_dbus_arg_info *) iface_entry->signals[i].arguments);
     863                 :            :     }
     864                 :            : 
     865                 :          0 :     pa_xfree(iface_entry->signals);
     866                 :          0 :     pa_xfree(iface_entry);
     867                 :            : 
     868         [ #  # ]:          0 :     if (pa_hashmap_isempty(obj_entry->interfaces)) {
     869                 :          0 :         unregister_object(p, obj_entry);
     870                 :            : 
     871                 :          0 :         pa_hashmap_remove(p->objects, path);
     872                 :          0 :         pa_xfree(obj_entry->path);
     873                 :          0 :         pa_hashmap_free(obj_entry->interfaces, NULL, NULL);
     874                 :          0 :         pa_xfree(obj_entry->introspection);
     875                 :          0 :         pa_xfree(obj_entry);
     876                 :            :     }
     877                 :            : 
     878                 :            :     return 0;
     879                 :            : }
     880                 :            : 
     881                 :          0 : static void register_all_objects(pa_dbus_protocol *p, DBusConnection *conn) {
     882                 :            :     struct object_entry *obj_entry;
     883                 :          0 :     void *state = NULL;
     884                 :            : 
     885         [ #  # ]:          0 :     pa_assert(p);
     886         [ #  # ]:          0 :     pa_assert(conn);
     887                 :            : 
     888         [ #  # ]:          0 :     PA_HASHMAP_FOREACH(obj_entry, p->objects, state)
     889         [ #  # ]:          0 :         pa_assert_se(dbus_connection_register_object_path(conn, obj_entry->path, &vtable, p));
     890                 :          0 : }
     891                 :            : 
     892                 :          0 : int pa_dbus_protocol_register_connection(pa_dbus_protocol *p, DBusConnection *conn, pa_client *client) {
     893                 :            :     struct connection_entry *conn_entry;
     894                 :            : 
     895         [ #  # ]:          0 :     pa_assert(p);
     896         [ #  # ]:          0 :     pa_assert(conn);
     897         [ #  # ]:          0 :     pa_assert(client);
     898                 :            : 
     899         [ #  # ]:          0 :     if (pa_hashmap_get(p->connections, conn))
     900                 :            :         return -1; /* The connection was already registered. */
     901                 :            : 
     902                 :          0 :     register_all_objects(p, conn);
     903                 :            : 
     904                 :          0 :     conn_entry = pa_xnew(struct connection_entry, 1);
     905                 :          0 :     conn_entry->connection = dbus_connection_ref(conn);
     906                 :          0 :     conn_entry->client = client;
     907                 :          0 :     conn_entry->listening_for_all_signals = FALSE;
     908                 :          0 :     conn_entry->all_signals_objects = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     909                 :          0 :     conn_entry->listening_signals = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     910                 :            : 
     911                 :          0 :     pa_hashmap_put(p->connections, conn, conn_entry);
     912                 :            : 
     913                 :          0 :     return 0;
     914                 :            : }
     915                 :            : 
     916                 :          0 : static void unregister_all_objects(pa_dbus_protocol *p, DBusConnection *conn) {
     917                 :            :     struct object_entry *obj_entry;
     918                 :          0 :     void *state = NULL;
     919                 :            : 
     920         [ #  # ]:          0 :     pa_assert(p);
     921         [ #  # ]:          0 :     pa_assert(conn);
     922                 :            : 
     923         [ #  # ]:          0 :     PA_HASHMAP_FOREACH(obj_entry, p->objects, state)
     924         [ #  # ]:          0 :         pa_assert_se(dbus_connection_unregister_object_path(conn, obj_entry->path));
     925                 :          0 : }
     926                 :            : 
     927                 :            : static struct signal_paths_entry *signal_paths_entry_new(const char *signal_name) {
     928                 :          0 :     struct signal_paths_entry *e = NULL;
     929                 :            : 
     930         [ #  # ]:          0 :     pa_assert(signal_name);
     931                 :            : 
     932                 :          0 :     e = pa_xnew0(struct signal_paths_entry, 1);
     933                 :          0 :     e->signal = pa_xstrdup(signal_name);
     934                 :          0 :     e->paths = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     935                 :            : 
     936                 :            :     return e;
     937                 :            : }
     938                 :            : 
     939                 :          0 : static void signal_paths_entry_free(struct signal_paths_entry *e) {
     940                 :          0 :     char *path = NULL;
     941                 :            : 
     942         [ #  # ]:          0 :     pa_assert(e);
     943                 :            : 
     944                 :          0 :     pa_xfree(e->signal);
     945                 :            : 
     946         [ #  # ]:          0 :     while ((path = pa_idxset_steal_first(e->paths, NULL)))
     947                 :          0 :         pa_xfree(path);
     948                 :            : 
     949                 :          0 :     pa_idxset_free(e->paths, NULL, NULL);
     950                 :          0 :     pa_xfree(e);
     951                 :          0 : }
     952                 :            : 
     953                 :          0 : int pa_dbus_protocol_unregister_connection(pa_dbus_protocol *p, DBusConnection *conn) {
     954                 :          0 :     struct connection_entry *conn_entry = NULL;
     955                 :          0 :     struct signal_paths_entry *signal_paths_entry = NULL;
     956                 :          0 :     char *object_path = NULL;
     957                 :            : 
     958         [ #  # ]:          0 :     pa_assert(p);
     959         [ #  # ]:          0 :     pa_assert(conn);
     960                 :            : 
     961         [ #  # ]:          0 :     if (!(conn_entry = pa_hashmap_remove(p->connections, conn)))
     962                 :            :         return -1;
     963                 :            : 
     964                 :          0 :     unregister_all_objects(p, conn);
     965                 :            : 
     966                 :          0 :     dbus_connection_unref(conn_entry->connection);
     967                 :            : 
     968         [ #  # ]:          0 :     while ((object_path = pa_idxset_steal_first(conn_entry->all_signals_objects, NULL)))
     969                 :          0 :         pa_xfree(object_path);
     970                 :            : 
     971                 :          0 :     pa_idxset_free(conn_entry->all_signals_objects, NULL, NULL);
     972                 :            : 
     973         [ #  # ]:          0 :     while ((signal_paths_entry = pa_hashmap_steal_first(conn_entry->listening_signals)))
     974                 :          0 :         signal_paths_entry_free(signal_paths_entry);
     975                 :            : 
     976                 :          0 :     pa_hashmap_free(conn_entry->listening_signals, NULL, NULL);
     977                 :          0 :     pa_xfree(conn_entry);
     978                 :            : 
     979                 :          0 :     return 0;
     980                 :            : }
     981                 :            : 
     982                 :          0 : pa_client *pa_dbus_protocol_get_client(pa_dbus_protocol *p, DBusConnection *conn) {
     983                 :            :     struct connection_entry *conn_entry;
     984                 :            : 
     985         [ #  # ]:          0 :     pa_assert(p);
     986         [ #  # ]:          0 :     pa_assert(conn);
     987                 :            : 
     988         [ #  # ]:          0 :     if (!(conn_entry = pa_hashmap_get(p->connections, conn)))
     989                 :            :         return NULL;
     990                 :            : 
     991                 :          0 :     return conn_entry->client;
     992                 :            : }
     993                 :            : 
     994                 :          0 : void pa_dbus_protocol_add_signal_listener(
     995                 :            :         pa_dbus_protocol *p,
     996                 :            :         DBusConnection *conn,
     997                 :            :         const char *signal_name,
     998                 :            :         char **objects,
     999                 :            :         unsigned n_objects) {
    1000                 :          0 :     struct connection_entry *conn_entry = NULL;
    1001                 :          0 :     struct signal_paths_entry *signal_paths_entry = NULL;
    1002                 :          0 :     char *object_path = NULL;
    1003                 :          0 :     unsigned i = 0;
    1004                 :            : 
    1005         [ #  # ]:          0 :     pa_assert(p);
    1006         [ #  # ]:          0 :     pa_assert(conn);
    1007         [ #  # ]:          0 :     pa_assert(objects || n_objects == 0);
    1008                 :            : 
    1009         [ #  # ]:          0 :     pa_assert_se((conn_entry = pa_hashmap_get(p->connections, conn)));
    1010                 :            : 
    1011                 :            :     /* all_signals_objects will either be emptied or replaced with new objects,
    1012                 :            :      * so we empty it here unconditionally. If listening_for_all_signals is
    1013                 :            :      * currently FALSE, the idxset is empty already so this does nothing. */
    1014         [ #  # ]:          0 :     while ((object_path = pa_idxset_steal_first(conn_entry->all_signals_objects, NULL)))
    1015                 :          0 :         pa_xfree(object_path);
    1016                 :            : 
    1017         [ #  # ]:          0 :     if (signal_name) {
    1018                 :          0 :         conn_entry->listening_for_all_signals = FALSE;
    1019                 :            : 
    1020                 :            :         /* Replace the old signal paths entry for this signal with a new
    1021                 :            :          * one. */
    1022         [ #  # ]:          0 :         if ((signal_paths_entry = pa_hashmap_remove(conn_entry->listening_signals, signal_name)))
    1023                 :          0 :             signal_paths_entry_free(signal_paths_entry);
    1024                 :          0 :         signal_paths_entry = signal_paths_entry_new(signal_name);
    1025                 :            : 
    1026         [ #  # ]:          0 :         for (i = 0; i < n_objects; ++i)
    1027                 :          0 :             pa_idxset_put(signal_paths_entry->paths, pa_xstrdup(objects[i]), NULL);
    1028                 :            : 
    1029                 :          0 :         pa_hashmap_put(conn_entry->listening_signals, signal_paths_entry->signal, signal_paths_entry);
    1030                 :            : 
    1031                 :            :     } else {
    1032                 :          0 :         conn_entry->listening_for_all_signals = TRUE;
    1033                 :            : 
    1034                 :            :         /* We're not interested in individual signals anymore, so let's empty
    1035                 :            :          * listening_signals. */
    1036         [ #  # ]:          0 :         while ((signal_paths_entry = pa_hashmap_steal_first(conn_entry->listening_signals)))
    1037                 :          0 :             signal_paths_entry_free(signal_paths_entry);
    1038                 :            : 
    1039         [ #  # ]:          0 :         for (i = 0; i < n_objects; ++i)
    1040                 :          0 :             pa_idxset_put(conn_entry->all_signals_objects, pa_xstrdup(objects[i]), NULL);
    1041                 :            :     }
    1042                 :          0 : }
    1043                 :            : 
    1044                 :          0 : void pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection *conn, const char *signal_name) {
    1045                 :          0 :     struct connection_entry *conn_entry = NULL;
    1046                 :          0 :     struct signal_paths_entry *signal_paths_entry = NULL;
    1047                 :            : 
    1048         [ #  # ]:          0 :     pa_assert(p);
    1049         [ #  # ]:          0 :     pa_assert(conn);
    1050                 :            : 
    1051         [ #  # ]:          0 :     pa_assert_se((conn_entry = pa_hashmap_get(p->connections, conn)));
    1052                 :            : 
    1053         [ #  # ]:          0 :     if (signal_name) {
    1054         [ #  # ]:          0 :         if ((signal_paths_entry = pa_hashmap_get(conn_entry->listening_signals, signal_name)))
    1055                 :          0 :             signal_paths_entry_free(signal_paths_entry);
    1056                 :            : 
    1057                 :            :     } else {
    1058                 :            :         char *object_path;
    1059                 :            : 
    1060                 :          0 :         conn_entry->listening_for_all_signals = FALSE;
    1061                 :            : 
    1062         [ #  # ]:          0 :         while ((object_path = pa_idxset_steal_first(conn_entry->all_signals_objects, NULL)))
    1063                 :          0 :             pa_xfree(object_path);
    1064                 :            : 
    1065         [ #  # ]:          0 :         while ((signal_paths_entry = pa_hashmap_steal_first(conn_entry->listening_signals)))
    1066                 :          0 :             signal_paths_entry_free(signal_paths_entry);
    1067                 :            :     }
    1068                 :          0 : }
    1069                 :            : 
    1070                 :          0 : void pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal_msg) {
    1071                 :            :     struct connection_entry *conn_entry;
    1072                 :            :     struct signal_paths_entry *signal_paths_entry;
    1073                 :          0 :     void *state = NULL;
    1074                 :            :     DBusMessage *signal_copy;
    1075                 :            :     char *signal_string;
    1076                 :            : 
    1077         [ #  # ]:          0 :     pa_assert(p);
    1078         [ #  # ]:          0 :     pa_assert(signal_msg);
    1079         [ #  # ]:          0 :     pa_assert(dbus_message_get_type(signal_msg) == DBUS_MESSAGE_TYPE_SIGNAL);
    1080         [ #  # ]:          0 :     pa_assert(dbus_message_get_path(signal_msg));
    1081         [ #  # ]:          0 :     pa_assert(dbus_message_get_interface(signal_msg));
    1082         [ #  # ]:          0 :     pa_assert(dbus_message_get_member(signal_msg));
    1083                 :            : 
    1084                 :          0 :     signal_string = pa_sprintf_malloc("%s.%s", dbus_message_get_interface(signal_msg), dbus_message_get_member(signal_msg));
    1085                 :            : 
    1086         [ #  # ]:          0 :     PA_HASHMAP_FOREACH(conn_entry, p->connections, state) {
    1087         [ #  # ]:          0 :         if ((conn_entry->listening_for_all_signals /* Case 1: listening for all signals */
    1088         [ #  # ]:          0 :              && (pa_idxset_get_by_data(conn_entry->all_signals_objects, dbus_message_get_path(signal_msg), NULL)
    1089         [ #  # ]:          0 :                  || pa_idxset_isempty(conn_entry->all_signals_objects)))
    1090                 :            : 
    1091         [ #  # ]:          0 :             || (!conn_entry->listening_for_all_signals /* Case 2: not listening for all signals */
    1092         [ #  # ]:          0 :                 && (signal_paths_entry = pa_hashmap_get(conn_entry->listening_signals, signal_string))
    1093         [ #  # ]:          0 :                 && (pa_idxset_get_by_data(signal_paths_entry->paths, dbus_message_get_path(signal_msg), NULL)
    1094         [ #  # ]:          0 :                     || pa_idxset_isempty(signal_paths_entry->paths)))) {
    1095                 :            : 
    1096         [ #  # ]:          0 :             pa_assert_se(signal_copy = dbus_message_copy(signal_msg));
    1097         [ #  # ]:          0 :             pa_assert_se(dbus_connection_send(conn_entry->connection, signal_copy, NULL));
    1098                 :          0 :             dbus_message_unref(signal_copy);
    1099                 :            :         }
    1100                 :            :     }
    1101                 :            : 
    1102                 :          0 :     pa_xfree(signal_string);
    1103                 :          0 : }
    1104                 :            : 
    1105                 :          0 : const char **pa_dbus_protocol_get_extensions(pa_dbus_protocol *p, unsigned *n) {
    1106                 :            :     const char **extensions;
    1107                 :            :     const char *ext_name;
    1108                 :          0 :     void *state = NULL;
    1109                 :          0 :     unsigned i = 0;
    1110                 :            : 
    1111         [ #  # ]:          0 :     pa_assert(p);
    1112         [ #  # ]:          0 :     pa_assert(n);
    1113                 :            : 
    1114                 :          0 :     *n = pa_idxset_size(p->extensions);
    1115                 :            : 
    1116         [ #  # ]:          0 :     if (*n <= 0)
    1117                 :            :         return NULL;
    1118                 :            : 
    1119                 :          0 :     extensions = pa_xnew(const char *, *n);
    1120                 :            : 
    1121         [ #  # ]:          0 :     while ((ext_name = pa_idxset_iterate(p->extensions, &state, NULL)))
    1122                 :          0 :         extensions[i++] = ext_name;
    1123                 :            : 
    1124                 :            :     return extensions;
    1125                 :            : }
    1126                 :            : 
    1127                 :          0 : int pa_dbus_protocol_register_extension(pa_dbus_protocol *p, const char *name) {
    1128                 :            :     char *internal_name;
    1129                 :            : 
    1130         [ #  # ]:          0 :     pa_assert(p);
    1131         [ #  # ]:          0 :     pa_assert(name);
    1132                 :            : 
    1133                 :          0 :     internal_name = pa_xstrdup(name);
    1134                 :            : 
    1135         [ #  # ]:          0 :     if (pa_idxset_put(p->extensions, internal_name, NULL) < 0) {
    1136                 :          0 :         pa_xfree(internal_name);
    1137                 :          0 :         return -1;
    1138                 :            :     }
    1139                 :            : 
    1140                 :          0 :     pa_hook_fire(&p->hooks[PA_DBUS_PROTOCOL_HOOK_EXTENSION_REGISTERED], internal_name);
    1141                 :            : 
    1142                 :          0 :     return 0;
    1143                 :            : }
    1144                 :            : 
    1145                 :          0 : int pa_dbus_protocol_unregister_extension(pa_dbus_protocol *p, const char *name) {
    1146                 :            :     char *internal_name;
    1147                 :            : 
    1148         [ #  # ]:          0 :     pa_assert(p);
    1149         [ #  # ]:          0 :     pa_assert(name);
    1150                 :            : 
    1151         [ #  # ]:          0 :     if (!(internal_name = pa_idxset_remove_by_data(p->extensions, name, NULL)))
    1152                 :            :         return -1;
    1153                 :            : 
    1154                 :          0 :     pa_hook_fire(&p->hooks[PA_DBUS_PROTOCOL_HOOK_EXTENSION_UNREGISTERED], internal_name);
    1155                 :            : 
    1156                 :          0 :     pa_xfree(internal_name);
    1157                 :            : 
    1158                 :          0 :     return 0;
    1159                 :            : }
    1160                 :            : 
    1161                 :          0 : pa_hook_slot *pa_dbus_protocol_hook_connect(
    1162                 :            :         pa_dbus_protocol *p,
    1163                 :            :         pa_dbus_protocol_hook_t hook,
    1164                 :            :         pa_hook_priority_t prio,
    1165                 :            :         pa_hook_cb_t cb,
    1166                 :            :         void *data) {
    1167         [ #  # ]:          0 :     pa_assert(p);
    1168         [ #  # ]:          0 :     pa_assert(hook < PA_DBUS_PROTOCOL_HOOK_MAX);
    1169         [ #  # ]:          0 :     pa_assert(cb);
    1170                 :            : 
    1171                 :          0 :     return pa_hook_connect(&p->hooks[hook], prio, cb, data);
    1172                 :            : }

Generated by: LCOV version 1.9