mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-06-09 19:48:21 +02:00
The o.fd.DBus interface needs to remain available on arbitrary object paths for backwards compatibility, and the Introspectable interface is genuinely useful, but everything else can be skipped. This is arguably an incompatible change for the undocumented Verbose interface, and for the GetAllMatchRules method on the undocumented Stats interface: previously those were available at all object paths. Reviewed-by: Philip Withnall <withnall@endlessm.com> [smcv: Adjust comments, enum order, variable naming as per Philip's review] Signed-off-by: Simon McVittie <smcv@collabora.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=101256
338 lines
11 KiB
C
338 lines
11 KiB
C
/* 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 <config.h>
|
|
#include "stats.h"
|
|
|
|
#include <dbus/dbus-asv-util.h>
|
|
#include <dbus/dbus-internals.h>
|
|
#include <dbus/dbus-connection-internal.h>
|
|
|
|
#include "connection.h"
|
|
#include "driver.h"
|
|
#include "services.h"
|
|
#include "signals.h"
|
|
#include "utils.h"
|
|
|
|
#ifdef DBUS_ENABLE_STATS
|
|
|
|
dbus_bool_t
|
|
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 TRUE;
|
|
|
|
oom:
|
|
if (reply != NULL)
|
|
dbus_message_unref (reply);
|
|
|
|
BUS_SET_OOM (error);
|
|
return FALSE;
|
|
}
|
|
|
|
dbus_bool_t
|
|
bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
|
|
BusTransaction *transaction,
|
|
DBusMessage *message,
|
|
DBusError *error)
|
|
{
|
|
const char *bus_name = NULL;
|
|
DBusString bus_name_str;
|
|
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;
|
|
BusRegistry *registry;
|
|
BusService *service;
|
|
DBusConnection *stats_connection;
|
|
|
|
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
|
|
|
registry = bus_connection_get_registry (caller_connection);
|
|
|
|
if (! dbus_message_get_args (message, error,
|
|
DBUS_TYPE_STRING, &bus_name,
|
|
DBUS_TYPE_INVALID))
|
|
return FALSE;
|
|
|
|
_dbus_string_init_const (&bus_name_str, bus_name);
|
|
service = bus_registry_lookup (registry, &bus_name_str);
|
|
|
|
if (service == NULL)
|
|
{
|
|
dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
|
|
"Bus name '%s' has no owner", bus_name);
|
|
return FALSE;
|
|
}
|
|
|
|
stats_connection = bus_service_get_primary_owners_connection (service);
|
|
_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_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 TRUE;
|
|
|
|
oom:
|
|
if (reply != NULL)
|
|
dbus_message_unref (reply);
|
|
|
|
BUS_SET_OOM (error);
|
|
return 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
|