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