Home | History | Annotate | Download | only in bus
      1 /* stats.c - statistics from the bus driver
      2  *
      3  * Licensed under the Academic Free License version 2.1
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program; if not, write to the Free Software
     17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     18  * 02110-1301 USA
     19  */
     20 
     21 #include <config.h>
     22 #include "stats.h"
     23 
     24 #include <dbus/dbus-internals.h>
     25 #include <dbus/dbus-connection-internal.h>
     26 
     27 #include "connection.h"
     28 #include "services.h"
     29 #include "utils.h"
     30 
     31 #ifdef DBUS_ENABLE_STATS
     32 
     33 static DBusMessage *
     34 new_asv_reply (DBusMessage      *message,
     35                DBusMessageIter  *iter,
     36                DBusMessageIter  *arr_iter)
     37 {
     38   DBusMessage *reply = dbus_message_new_method_return (message);
     39 
     40   if (reply == NULL)
     41     return NULL;
     42 
     43   dbus_message_iter_init_append (reply, iter);
     44 
     45   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{sv}",
     46                                          arr_iter))
     47     {
     48       dbus_message_unref (reply);
     49       return NULL;
     50     }
     51 
     52   return reply;
     53 }
     54 
     55 static dbus_bool_t
     56 open_asv_entry (DBusMessageIter *arr_iter,
     57                 DBusMessageIter *entry_iter,
     58                 const char      *key,
     59                 const char      *type,
     60                 DBusMessageIter *var_iter)
     61 {
     62   if (!dbus_message_iter_open_container (arr_iter, DBUS_TYPE_DICT_ENTRY,
     63                                          NULL, entry_iter))
     64     return FALSE;
     65 
     66   if (!dbus_message_iter_append_basic (entry_iter, DBUS_TYPE_STRING, &key))
     67     {
     68       dbus_message_iter_abandon_container (arr_iter, entry_iter);
     69       return FALSE;
     70     }
     71 
     72   if (!dbus_message_iter_open_container (entry_iter, DBUS_TYPE_VARIANT,
     73                                          type, var_iter))
     74     {
     75       dbus_message_iter_abandon_container (arr_iter, entry_iter);
     76       return FALSE;
     77     }
     78 
     79   return TRUE;
     80 }
     81 
     82 static dbus_bool_t
     83 close_asv_entry (DBusMessageIter *arr_iter,
     84                  DBusMessageIter *entry_iter,
     85                  DBusMessageIter *var_iter)
     86 {
     87   if (!dbus_message_iter_close_container (entry_iter, var_iter))
     88     {
     89       dbus_message_iter_abandon_container (arr_iter, entry_iter);
     90       return FALSE;
     91     }
     92 
     93   if (!dbus_message_iter_close_container (arr_iter, entry_iter))
     94     return FALSE;
     95 
     96   return TRUE;
     97 }
     98 
     99 static dbus_bool_t
    100 close_asv_reply (DBusMessageIter *iter,
    101                  DBusMessageIter *arr_iter)
    102 {
    103   return dbus_message_iter_close_container (iter, arr_iter);
    104 }
    105 
    106 static void
    107 abandon_asv_entry (DBusMessageIter *arr_iter,
    108                    DBusMessageIter *entry_iter,
    109                    DBusMessageIter *var_iter)
    110 {
    111   dbus_message_iter_abandon_container (entry_iter, var_iter);
    112   dbus_message_iter_abandon_container (arr_iter, entry_iter);
    113 }
    114 
    115 static void
    116 abandon_asv_reply (DBusMessageIter *iter,
    117                  DBusMessageIter *arr_iter)
    118 {
    119   dbus_message_iter_abandon_container (iter, arr_iter);
    120 }
    121 
    122 static dbus_bool_t
    123 asv_add_uint32 (DBusMessageIter *iter,
    124                 DBusMessageIter *arr_iter,
    125                 const char *key,
    126                 dbus_uint32_t value)
    127 {
    128   DBusMessageIter entry_iter, var_iter;
    129 
    130   if (!open_asv_entry (arr_iter, &entry_iter, key, DBUS_TYPE_UINT32_AS_STRING,
    131                        &var_iter))
    132     goto oom;
    133 
    134   if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_UINT32,
    135                                        &value))
    136     {
    137       abandon_asv_entry (arr_iter, &entry_iter, &var_iter);
    138       goto oom;
    139     }
    140 
    141   if (!close_asv_entry (arr_iter, &entry_iter, &var_iter))
    142     goto oom;
    143 
    144   return TRUE;
    145 
    146 oom:
    147   abandon_asv_reply (iter, arr_iter);
    148   return FALSE;
    149 }
    150 
    151 static dbus_bool_t
    152 asv_add_string (DBusMessageIter *iter,
    153                 DBusMessageIter *arr_iter,
    154                 const char *key,
    155                 const char *value)
    156 {
    157   DBusMessageIter entry_iter, var_iter;
    158 
    159   if (!open_asv_entry (arr_iter, &entry_iter, key, DBUS_TYPE_STRING_AS_STRING,
    160                        &var_iter))
    161     goto oom;
    162 
    163   if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_STRING,
    164                                        &value))
    165     {
    166       abandon_asv_entry (arr_iter, &entry_iter, &var_iter);
    167       goto oom;
    168     }
    169 
    170   if (!close_asv_entry (arr_iter, &entry_iter, &var_iter))
    171     goto oom;
    172 
    173   return TRUE;
    174 
    175 oom:
    176   abandon_asv_reply (iter, arr_iter);
    177   return FALSE;
    178 }
    179 
    180 dbus_bool_t
    181 bus_stats_handle_get_stats (DBusConnection *connection,
    182                             BusTransaction *transaction,
    183                             DBusMessage    *message,
    184                             DBusError      *error)
    185 {
    186   BusConnections *connections;
    187   DBusMessage *reply = NULL;
    188   DBusMessageIter iter, arr_iter;
    189   static dbus_uint32_t stats_serial = 0;
    190   dbus_uint32_t in_use, in_free_list, allocated;
    191 
    192   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    193 
    194   connections = bus_transaction_get_connections (transaction);
    195 
    196   reply = new_asv_reply (message, &iter, &arr_iter);
    197 
    198   if (reply == NULL)
    199     goto oom;
    200 
    201   /* Globals */
    202 
    203   if (!asv_add_uint32 (&iter, &arr_iter, "Serial", stats_serial++))
    204     goto oom;
    205 
    206   _dbus_list_get_stats (&in_use, &in_free_list, &allocated);
    207   if (!asv_add_uint32 (&iter, &arr_iter, "ListMemPoolUsedBytes", in_use) ||
    208       !asv_add_uint32 (&iter, &arr_iter, "ListMemPoolCachedBytes",
    209                        in_free_list) ||
    210       !asv_add_uint32 (&iter, &arr_iter, "ListMemPoolAllocatedBytes",
    211                        allocated))
    212     goto oom;
    213 
    214   /* Connections */
    215 
    216   if (!asv_add_uint32 (&iter, &arr_iter, "ActiveConnections",
    217         bus_connections_get_n_active (connections)) ||
    218       !asv_add_uint32 (&iter, &arr_iter, "IncompleteConnections",
    219         bus_connections_get_n_incomplete (connections)) ||
    220       !asv_add_uint32 (&iter, &arr_iter, "MatchRules",
    221         bus_connections_get_total_match_rules (connections)) ||
    222       !asv_add_uint32 (&iter, &arr_iter, "PeakMatchRules",
    223         bus_connections_get_peak_match_rules (connections)) ||
    224       !asv_add_uint32 (&iter, &arr_iter, "PeakMatchRulesPerConnection",
    225         bus_connections_get_peak_match_rules_per_conn (connections)) ||
    226       !asv_add_uint32 (&iter, &arr_iter, "BusNames",
    227         bus_connections_get_total_bus_names (connections)) ||
    228       !asv_add_uint32 (&iter, &arr_iter, "PeakBusNames",
    229         bus_connections_get_peak_bus_names (connections)) ||
    230       !asv_add_uint32 (&iter, &arr_iter, "PeakBusNamesPerConnection",
    231         bus_connections_get_peak_bus_names_per_conn (connections)))
    232     goto oom;
    233 
    234   /* end */
    235 
    236   if (!close_asv_reply (&iter, &arr_iter))
    237     goto oom;
    238 
    239   if (!bus_transaction_send_from_driver (transaction, connection, reply))
    240     goto oom;
    241 
    242   dbus_message_unref (reply);
    243   return TRUE;
    244 
    245 oom:
    246   if (reply != NULL)
    247     dbus_message_unref (reply);
    248 
    249   BUS_SET_OOM (error);
    250   return FALSE;
    251 }
    252 
    253 dbus_bool_t
    254 bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
    255                                        BusTransaction *transaction,
    256                                        DBusMessage    *message,
    257                                        DBusError      *error)
    258 {
    259   const char *bus_name = NULL;
    260   DBusString bus_name_str;
    261   DBusMessage *reply = NULL;
    262   DBusMessageIter iter, arr_iter;
    263   static dbus_uint32_t stats_serial = 0;
    264   dbus_uint32_t in_messages, in_bytes, in_fds, in_peak_bytes, in_peak_fds;
    265   dbus_uint32_t out_messages, out_bytes, out_fds, out_peak_bytes, out_peak_fds;
    266   BusRegistry *registry;
    267   BusService *service;
    268   DBusConnection *stats_connection;
    269 
    270   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    271 
    272   registry = bus_connection_get_registry (caller_connection);
    273 
    274   if (! dbus_message_get_args (message, error,
    275                                DBUS_TYPE_STRING, &bus_name,
    276                                DBUS_TYPE_INVALID))
    277       return FALSE;
    278 
    279   _dbus_string_init_const (&bus_name_str, bus_name);
    280   service = bus_registry_lookup (registry, &bus_name_str);
    281 
    282   if (service == NULL)
    283     {
    284       dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
    285                       "Bus name '%s' has no owner", bus_name);
    286       return FALSE;
    287     }
    288 
    289   stats_connection = bus_service_get_primary_owners_connection (service);
    290   _dbus_assert (stats_connection != NULL);
    291 
    292   reply = new_asv_reply (message, &iter, &arr_iter);
    293 
    294   if (reply == NULL)
    295     goto oom;
    296 
    297   /* Bus daemon per-connection stats */
    298 
    299   if (!asv_add_uint32 (&iter, &arr_iter, "Serial", stats_serial++) ||
    300       !asv_add_uint32 (&iter, &arr_iter, "MatchRules",
    301         bus_connection_get_n_match_rules (stats_connection)) ||
    302       !asv_add_uint32 (&iter, &arr_iter, "PeakMatchRules",
    303         bus_connection_get_peak_match_rules (stats_connection)) ||
    304       !asv_add_uint32 (&iter, &arr_iter, "BusNames",
    305         bus_connection_get_n_services_owned (stats_connection)) ||
    306       !asv_add_uint32 (&iter, &arr_iter, "PeakBusNames",
    307         bus_connection_get_peak_bus_names (stats_connection)) ||
    308       !asv_add_string (&iter, &arr_iter, "UniqueName",
    309         bus_connection_get_name (stats_connection)))
    310     goto oom;
    311 
    312   /* DBusConnection per-connection stats */
    313 
    314   _dbus_connection_get_stats (stats_connection,
    315                               &in_messages, &in_bytes, &in_fds,
    316                               &in_peak_bytes, &in_peak_fds,
    317                               &out_messages, &out_bytes, &out_fds,
    318                               &out_peak_bytes, &out_peak_fds);
    319 
    320   if (!asv_add_uint32 (&iter, &arr_iter, "IncomingMessages", in_messages) ||
    321       !asv_add_uint32 (&iter, &arr_iter, "IncomingBytes", in_bytes) ||
    322       !asv_add_uint32 (&iter, &arr_iter, "IncomingFDs", in_fds) ||
    323       !asv_add_uint32 (&iter, &arr_iter, "PeakIncomingBytes", in_peak_bytes) ||
    324       !asv_add_uint32 (&iter, &arr_iter, "PeakIncomingFDs", in_peak_fds) ||
    325       !asv_add_uint32 (&iter, &arr_iter, "OutgoingMessages", out_messages) ||
    326       !asv_add_uint32 (&iter, &arr_iter, "OutgoingBytes", out_bytes) ||
    327       !asv_add_uint32 (&iter, &arr_iter, "OutgoingFDs", out_fds) ||
    328       !asv_add_uint32 (&iter, &arr_iter, "PeakOutgoingBytes", out_peak_bytes) ||
    329       !asv_add_uint32 (&iter, &arr_iter, "PeakOutgoingFDs", out_peak_fds))
    330     goto oom;
    331 
    332   /* end */
    333 
    334   if (!close_asv_reply (&iter, &arr_iter))
    335     goto oom;
    336 
    337   if (!bus_transaction_send_from_driver (transaction, caller_connection,
    338                                          reply))
    339     goto oom;
    340 
    341   dbus_message_unref (reply);
    342   return TRUE;
    343 
    344 oom:
    345   if (reply != NULL)
    346     dbus_message_unref (reply);
    347 
    348   BUS_SET_OOM (error);
    349   return FALSE;
    350 }
    351 
    352 #endif
    353