/* stats.c - statistics from the bus driver * * Copyright © 2011-2012 Nokia Corporation * Copyright © 2012-2013 Collabora Ltd. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #include #include "stats.h" #include #include #include #include "connection.h" #include "driver.h" #include "services.h" #include "signals.h" #include "utils.h" #ifdef DBUS_ENABLE_STATS BusResult bus_stats_handle_get_stats (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { BusContext *context; BusConnections *connections; DBusMessage *reply = NULL; DBusMessageIter iter, arr_iter; static dbus_uint32_t stats_serial = 0; dbus_uint32_t in_use, in_free_list, allocated; _DBUS_ASSERT_ERROR_IS_CLEAR (error); context = bus_transaction_get_context (transaction); connections = bus_context_get_connections (context); reply = _dbus_asv_new_method_return (message, &iter, &arr_iter); if (reply == NULL) goto oom; /* Globals */ _dbus_list_get_stats (&in_use, &in_free_list, &allocated); if (!_dbus_asv_add_uint32 (&arr_iter, "Serial", stats_serial++) || !_dbus_asv_add_uint32 (&arr_iter, "ListMemPoolUsedBytes", in_use) || !_dbus_asv_add_uint32 (&arr_iter, "ListMemPoolCachedBytes", in_free_list) || !_dbus_asv_add_uint32 (&arr_iter, "ListMemPoolAllocatedBytes", allocated)) { _dbus_asv_abandon (&iter, &arr_iter); goto oom; } /* Connections */ if (!_dbus_asv_add_uint32 (&arr_iter, "ActiveConnections", bus_connections_get_n_active (connections)) || !_dbus_asv_add_uint32 (&arr_iter, "IncompleteConnections", bus_connections_get_n_incomplete (connections)) || !_dbus_asv_add_uint32 (&arr_iter, "MatchRules", bus_connections_get_total_match_rules (connections)) || !_dbus_asv_add_uint32 (&arr_iter, "PeakMatchRules", bus_connections_get_peak_match_rules (connections)) || !_dbus_asv_add_uint32 (&arr_iter, "PeakMatchRulesPerConnection", bus_connections_get_peak_match_rules_per_conn (connections)) || !_dbus_asv_add_uint32 (&arr_iter, "BusNames", bus_connections_get_total_bus_names (connections)) || !_dbus_asv_add_uint32 (&arr_iter, "PeakBusNames", bus_connections_get_peak_bus_names (connections)) || !_dbus_asv_add_uint32 (&arr_iter, "PeakBusNamesPerConnection", bus_connections_get_peak_bus_names_per_conn (connections))) { _dbus_asv_abandon (&iter, &arr_iter); goto oom; } /* end */ if (!_dbus_asv_close (&iter, &arr_iter)) goto oom; if (!bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return BUS_RESULT_TRUE; oom: if (reply != NULL) dbus_message_unref (reply); BUS_SET_OOM (error); return BUS_RESULT_FALSE; } BusResult bus_stats_handle_get_connection_stats (DBusConnection *caller_connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { BusDriverFound found; DBusMessage *reply = NULL; DBusMessageIter iter, arr_iter; static dbus_uint32_t stats_serial = 0; dbus_uint32_t in_messages, in_bytes, in_fds, in_peak_bytes, in_peak_fds; dbus_uint32_t out_messages, out_bytes, out_fds, out_peak_bytes, out_peak_fds; DBusConnection *stats_connection; _DBUS_ASSERT_ERROR_IS_CLEAR (error); found = bus_driver_get_conn_helper (caller_connection, message, "statistics", NULL, &stats_connection, error); switch (found) { case BUS_DRIVER_FOUND_SELF: dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "GetConnectionStats is not meaningful for the " "message bus \"%s\" itself", DBUS_SERVICE_DBUS); goto failed; case BUS_DRIVER_FOUND_PEER: break; case BUS_DRIVER_FOUND_ERROR: /* fall through */ default: goto failed; } _dbus_assert (stats_connection != NULL); reply = _dbus_asv_new_method_return (message, &iter, &arr_iter); if (reply == NULL) goto oom; /* Bus daemon per-connection stats */ if (!_dbus_asv_add_uint32 (&arr_iter, "Serial", stats_serial++) || !_dbus_asv_add_uint32 (&arr_iter, "MatchRules", bus_connection_get_n_match_rules (stats_connection)) || !_dbus_asv_add_uint32 (&arr_iter, "PeakMatchRules", bus_connection_get_peak_match_rules (stats_connection)) || !_dbus_asv_add_uint32 (&arr_iter, "BusNames", bus_connection_get_n_services_owned (stats_connection)) || !_dbus_asv_add_uint32 (&arr_iter, "PeakBusNames", bus_connection_get_peak_bus_names (stats_connection)) || !_dbus_asv_add_string (&arr_iter, "UniqueName", bus_connection_get_name (stats_connection)) || !_dbus_asv_add_uint32 (&arr_iter, "PendingReplies", bus_connection_get_n_pending_replies (stats_connection)) || !_dbus_asv_add_uint32 (&arr_iter, "PeakPendingReplies", bus_connection_get_peak_pending_replies (stats_connection))) { _dbus_asv_abandon (&iter, &arr_iter); goto oom; } /* DBusConnection per-connection stats */ _dbus_connection_get_stats (stats_connection, &in_messages, &in_bytes, &in_fds, &in_peak_bytes, &in_peak_fds, &out_messages, &out_bytes, &out_fds, &out_peak_bytes, &out_peak_fds); if (!_dbus_asv_add_uint32 (&arr_iter, "IncomingMessages", in_messages) || !_dbus_asv_add_uint32 (&arr_iter, "IncomingBytes", in_bytes) || !_dbus_asv_add_uint32 (&arr_iter, "IncomingFDs", in_fds) || !_dbus_asv_add_uint32 (&arr_iter, "PeakIncomingBytes", in_peak_bytes) || !_dbus_asv_add_uint32 (&arr_iter, "PeakIncomingFDs", in_peak_fds) || !_dbus_asv_add_uint32 (&arr_iter, "OutgoingMessages", out_messages) || !_dbus_asv_add_uint32 (&arr_iter, "OutgoingBytes", out_bytes) || !_dbus_asv_add_uint32 (&arr_iter, "OutgoingFDs", out_fds) || !_dbus_asv_add_uint32 (&arr_iter, "PeakOutgoingBytes", out_peak_bytes) || !_dbus_asv_add_uint32 (&arr_iter, "PeakOutgoingFDs", out_peak_fds)) { _dbus_asv_abandon (&iter, &arr_iter); goto oom; } /* end */ if (!_dbus_asv_close (&iter, &arr_iter)) goto oom; if (!bus_transaction_send_from_driver (transaction, caller_connection, reply)) goto oom; dbus_message_unref (reply); return BUS_RESULT_TRUE; oom: BUS_SET_OOM (error); /* fall through */ failed: if (reply != NULL) dbus_message_unref (reply); return BUS_RESULT_FALSE; } dbus_bool_t bus_stats_handle_get_all_match_rules (DBusConnection *caller_connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { BusContext *context; DBusString bus_name_str; DBusMessage *reply = NULL; DBusMessageIter iter, hash_iter, entry_iter, arr_iter; BusRegistry *registry; char **services = NULL; int services_len; DBusConnection *conn_filter = NULL; BusMatchmaker *matchmaker; int i; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (caller_connection); context = bus_transaction_get_context (transaction); matchmaker = bus_context_get_matchmaker (context); if (!bus_registry_list_services (registry, &services, &services_len)) return FALSE; reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; dbus_message_iter_init_append (reply, &iter); if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sas}", &hash_iter)) goto oom; for (i = 0 ; i < services_len ; i++) { BusService *service; /* To avoid duplicate entries, only look for unique names */ if (services[i][0] != ':') continue; _dbus_string_init_const (&bus_name_str, services[i]); service = bus_registry_lookup (registry, &bus_name_str); _dbus_assert (service != NULL); conn_filter = bus_service_get_primary_owners_connection (service); _dbus_assert (conn_filter != NULL); if (!dbus_message_iter_open_container (&hash_iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry_iter)) { dbus_message_iter_abandon_container (&iter, &hash_iter); goto oom; } if (!dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING, &services[i])) { dbus_message_iter_abandon_container (&hash_iter, &entry_iter); dbus_message_iter_abandon_container (&iter, &hash_iter); goto oom; } if (!dbus_message_iter_open_container (&entry_iter, DBUS_TYPE_ARRAY, "s", &arr_iter)) { dbus_message_iter_abandon_container (&hash_iter, &entry_iter); dbus_message_iter_abandon_container (&iter, &hash_iter); goto oom; } if (!bus_match_rule_dump (matchmaker, conn_filter, &arr_iter)) { dbus_message_iter_abandon_container (&entry_iter, &arr_iter); dbus_message_iter_abandon_container (&hash_iter, &entry_iter); dbus_message_iter_abandon_container (&iter, &hash_iter); goto oom; } if (!dbus_message_iter_close_container (&entry_iter, &arr_iter)) { dbus_message_iter_abandon_container (&hash_iter, &entry_iter); dbus_message_iter_abandon_container (&iter, &hash_iter); goto oom; } if (!dbus_message_iter_close_container (&hash_iter, &entry_iter)) { dbus_message_iter_abandon_container (&iter, &hash_iter); goto oom; } } if (!dbus_message_iter_close_container (&iter, &hash_iter)) goto oom; if (!bus_transaction_send_from_driver (transaction, caller_connection, reply)) goto oom; dbus_message_unref (reply); dbus_free_string_array (services); return TRUE; oom: if (reply != NULL) dbus_message_unref (reply); dbus_free_string_array (services); BUS_SET_OOM (error); return FALSE; } #endif