diff options
Diffstat (limited to 'bus/stats.c')
-rw-r--r-- | bus/stats.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/bus/stats.c b/bus/stats.c new file mode 100644 index 00000000..0cd36ca0 --- /dev/null +++ b/bus/stats.c @@ -0,0 +1,287 @@ +/* stats.c - statistics from the bus driver + * + * 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-internals.h> +#include <dbus/dbus-connection-internal.h> + +#include "connection.h" +#include "services.h" +#include "utils.h" + +#ifdef DBUS_ENABLE_STATS + +static DBusMessage * +new_asv_reply (DBusMessage *message, + DBusMessageIter *iter, + DBusMessageIter *arr_iter) +{ + DBusMessage *reply = dbus_message_new_method_return (message); + + if (reply == NULL) + return NULL; + + dbus_message_iter_init_append (reply, iter); + + if (!dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{sv}", + arr_iter)) + { + dbus_message_unref (reply); + return NULL; + } + + return reply; +} + +static dbus_bool_t +open_asv_entry (DBusMessageIter *arr_iter, + DBusMessageIter *entry_iter, + const char *key, + const char *type, + DBusMessageIter *var_iter) +{ + if (!dbus_message_iter_open_container (arr_iter, DBUS_TYPE_DICT_ENTRY, + NULL, entry_iter)) + return FALSE; + + if (!dbus_message_iter_append_basic (entry_iter, DBUS_TYPE_STRING, &key)) + { + dbus_message_iter_abandon_container (arr_iter, entry_iter); + return FALSE; + } + + if (!dbus_message_iter_open_container (entry_iter, DBUS_TYPE_VARIANT, + type, var_iter)) + { + dbus_message_iter_abandon_container (arr_iter, entry_iter); + return FALSE; + } + + return TRUE; +} + +static dbus_bool_t +close_asv_entry (DBusMessageIter *arr_iter, + DBusMessageIter *entry_iter, + DBusMessageIter *var_iter) +{ + if (!dbus_message_iter_close_container (entry_iter, var_iter)) + { + dbus_message_iter_abandon_container (arr_iter, entry_iter); + return FALSE; + } + + if (!dbus_message_iter_close_container (arr_iter, entry_iter)) + return FALSE; + + return TRUE; +} + +static dbus_bool_t +close_asv_reply (DBusMessageIter *iter, + DBusMessageIter *arr_iter) +{ + return dbus_message_iter_close_container (iter, arr_iter); +} + +static void +abandon_asv_entry (DBusMessageIter *arr_iter, + DBusMessageIter *entry_iter, + DBusMessageIter *var_iter) +{ + dbus_message_iter_abandon_container (entry_iter, var_iter); + dbus_message_iter_abandon_container (arr_iter, entry_iter); +} + +static void +abandon_asv_reply (DBusMessageIter *iter, + DBusMessageIter *arr_iter) +{ + dbus_message_iter_abandon_container (iter, arr_iter); +} + +static dbus_bool_t +asv_add_uint32 (DBusMessageIter *iter, + DBusMessageIter *arr_iter, + const char *key, + dbus_uint32_t value) +{ + DBusMessageIter entry_iter, var_iter; + + if (!open_asv_entry (arr_iter, &entry_iter, key, DBUS_TYPE_UINT32_AS_STRING, + &var_iter)) + goto oom; + + if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_UINT32, + &value)) + { + abandon_asv_entry (arr_iter, &entry_iter, &var_iter); + goto oom; + } + + if (!close_asv_entry (arr_iter, &entry_iter, &var_iter)) + goto oom; + + return TRUE; + +oom: + abandon_asv_reply (iter, arr_iter); + return FALSE; +} + +static dbus_bool_t +asv_add_string (DBusMessageIter *iter, + DBusMessageIter *arr_iter, + const char *key, + const char *value) +{ + DBusMessageIter entry_iter, var_iter; + + if (!open_asv_entry (arr_iter, &entry_iter, key, DBUS_TYPE_STRING_AS_STRING, + &var_iter)) + goto oom; + + if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_STRING, + &value)) + { + abandon_asv_entry (arr_iter, &entry_iter, &var_iter); + goto oom; + } + + if (!close_asv_entry (arr_iter, &entry_iter, &var_iter)) + goto oom; + + return TRUE; + +oom: + abandon_asv_reply (iter, arr_iter); + return FALSE; +} + +dbus_bool_t +bus_stats_handle_get_stats (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusConnections *connections; + DBusMessage *reply = NULL; + DBusMessageIter iter, arr_iter; + static dbus_uint32_t stats_serial = 0; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + connections = bus_transaction_get_connections (transaction); + + reply = new_asv_reply (message, &iter, &arr_iter); + + if (reply == NULL) + goto oom; + + if (!asv_add_uint32 (&iter, &arr_iter, "Serial", stats_serial++)) + goto oom; + + if (!close_asv_reply (&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; + dbus_uint32_t out_messages, out_bytes, out_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 = new_asv_reply (message, &iter, &arr_iter); + + if (reply == NULL) + goto oom; + + if (!asv_add_uint32 (&iter, &arr_iter, "Serial", stats_serial++) || + !asv_add_string (&iter, &arr_iter, "UniqueName", + bus_connection_get_name (stats_connection))) + goto oom; + + if (!close_asv_reply (&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; +} + +#endif |