summaryrefslogtreecommitdiff
path: root/bus/stats.c
diff options
context:
space:
mode:
Diffstat (limited to 'bus/stats.c')
-rw-r--r--bus/stats.c287
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