1 /* stats.c - statistics from the bus driver
2 *
3 * Copyright © 2011-2012 Nokia Corporation
4 * Copyright © 2012-2013 Collabora Ltd.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 */
23
24 #include <config.h>
25 #include "stats.h"
26
27 #include <dbus/dbus-asv-util.h>
28 #include <dbus/dbus-internals.h>
29 #include <dbus/dbus-connection-internal.h>
30
31 #include "connection.h"
32 #include "driver.h"
33 #include "services.h"
34 #include "signals.h"
35 #include "utils.h"
36
37 #ifdef DBUS_ENABLE_STATS
38
39 dbus_bool_t
bus_stats_handle_get_stats(DBusConnection * connection,BusTransaction * transaction,DBusMessage * message,DBusError * error)40 bus_stats_handle_get_stats (DBusConnection *connection,
41 BusTransaction *transaction,
42 DBusMessage *message,
43 DBusError *error)
44 {
45 BusContext *context;
46 BusConnections *connections;
47 DBusMessage *reply = NULL;
48 DBusMessageIter iter, arr_iter;
49 static dbus_uint32_t stats_serial = 0;
50 dbus_uint32_t in_use, in_free_list, allocated;
51
52 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
53
54 context = bus_transaction_get_context (transaction);
55 connections = bus_context_get_connections (context);
56
57 reply = _dbus_asv_new_method_return (message, &iter, &arr_iter);
58
59 if (reply == NULL)
60 goto oom;
61
62 /* Globals */
63
64 _dbus_list_get_stats (&in_use, &in_free_list, &allocated);
65
66 if (!_dbus_asv_add_uint32 (&arr_iter, "Serial", stats_serial++) ||
67 !_dbus_asv_add_uint32 (&arr_iter, "ListMemPoolUsedBytes", in_use) ||
68 !_dbus_asv_add_uint32 (&arr_iter, "ListMemPoolCachedBytes", in_free_list) ||
69 !_dbus_asv_add_uint32 (&arr_iter, "ListMemPoolAllocatedBytes", allocated))
70 {
71 _dbus_asv_abandon (&iter, &arr_iter);
72 goto oom;
73 }
74
75 /* Connections */
76
77 if (!_dbus_asv_add_uint32 (&arr_iter, "ActiveConnections",
78 bus_connections_get_n_active (connections)) ||
79 !_dbus_asv_add_uint32 (&arr_iter, "IncompleteConnections",
80 bus_connections_get_n_incomplete (connections)) ||
81 !_dbus_asv_add_uint32 (&arr_iter, "MatchRules",
82 bus_connections_get_total_match_rules (connections)) ||
83 !_dbus_asv_add_uint32 (&arr_iter, "PeakMatchRules",
84 bus_connections_get_peak_match_rules (connections)) ||
85 !_dbus_asv_add_uint32 (&arr_iter, "PeakMatchRulesPerConnection",
86 bus_connections_get_peak_match_rules_per_conn (connections)) ||
87 !_dbus_asv_add_uint32 (&arr_iter, "BusNames",
88 bus_connections_get_total_bus_names (connections)) ||
89 !_dbus_asv_add_uint32 (&arr_iter, "PeakBusNames",
90 bus_connections_get_peak_bus_names (connections)) ||
91 !_dbus_asv_add_uint32 (&arr_iter, "PeakBusNamesPerConnection",
92 bus_connections_get_peak_bus_names_per_conn (connections)))
93 {
94 _dbus_asv_abandon (&iter, &arr_iter);
95 goto oom;
96 }
97
98 /* end */
99
100 if (!_dbus_asv_close (&iter, &arr_iter))
101 goto oom;
102
103 if (!bus_transaction_send_from_driver (transaction, connection, reply))
104 goto oom;
105
106 dbus_message_unref (reply);
107 return TRUE;
108
109 oom:
110 if (reply != NULL)
111 dbus_message_unref (reply);
112
113 BUS_SET_OOM (error);
114 return FALSE;
115 }
116
117 dbus_bool_t
bus_stats_handle_get_connection_stats(DBusConnection * caller_connection,BusTransaction * transaction,DBusMessage * message,DBusError * error)118 bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
119 BusTransaction *transaction,
120 DBusMessage *message,
121 DBusError *error)
122 {
123 BusDriverFound found;
124 DBusMessage *reply = NULL;
125 DBusMessageIter iter, arr_iter;
126 static dbus_uint32_t stats_serial = 0;
127 dbus_uint32_t in_messages, in_bytes, in_fds, in_peak_bytes, in_peak_fds;
128 dbus_uint32_t out_messages, out_bytes, out_fds, out_peak_bytes, out_peak_fds;
129 DBusConnection *stats_connection;
130
131 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
132
133 found = bus_driver_get_conn_helper (caller_connection, message,
134 "statistics", NULL, &stats_connection,
135 error);
136
137 switch (found)
138 {
139 case BUS_DRIVER_FOUND_SELF:
140 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
141 "GetConnectionStats is not meaningful for the "
142 "message bus \"%s\" itself", DBUS_SERVICE_DBUS);
143 goto failed;
144
145 case BUS_DRIVER_FOUND_PEER:
146 break;
147
148 case BUS_DRIVER_FOUND_ERROR:
149 /* fall through */
150 default:
151 goto failed;
152 }
153
154 _dbus_assert (stats_connection != NULL);
155
156 reply = _dbus_asv_new_method_return (message, &iter, &arr_iter);
157
158 if (reply == NULL)
159 goto oom;
160
161 /* Bus daemon per-connection stats */
162
163 if (!_dbus_asv_add_uint32 (&arr_iter, "Serial", stats_serial++) ||
164 !_dbus_asv_add_uint32 (&arr_iter, "MatchRules",
165 bus_connection_get_n_match_rules (stats_connection)) ||
166 !_dbus_asv_add_uint32 (&arr_iter, "PeakMatchRules",
167 bus_connection_get_peak_match_rules (stats_connection)) ||
168 !_dbus_asv_add_uint32 (&arr_iter, "BusNames",
169 bus_connection_get_n_services_owned (stats_connection)) ||
170 !_dbus_asv_add_uint32 (&arr_iter, "PeakBusNames",
171 bus_connection_get_peak_bus_names (stats_connection)) ||
172 !_dbus_asv_add_string (&arr_iter, "UniqueName",
173 bus_connection_get_name (stats_connection)))
174 {
175 _dbus_asv_abandon (&iter, &arr_iter);
176 goto oom;
177 }
178
179 /* DBusConnection per-connection stats */
180
181 _dbus_connection_get_stats (stats_connection,
182 &in_messages, &in_bytes, &in_fds,
183 &in_peak_bytes, &in_peak_fds,
184 &out_messages, &out_bytes, &out_fds,
185 &out_peak_bytes, &out_peak_fds);
186
187 if (!_dbus_asv_add_uint32 (&arr_iter, "IncomingMessages", in_messages) ||
188 !_dbus_asv_add_uint32 (&arr_iter, "IncomingBytes", in_bytes) ||
189 !_dbus_asv_add_uint32 (&arr_iter, "IncomingFDs", in_fds) ||
190 !_dbus_asv_add_uint32 (&arr_iter, "PeakIncomingBytes", in_peak_bytes) ||
191 !_dbus_asv_add_uint32 (&arr_iter, "PeakIncomingFDs", in_peak_fds) ||
192 !_dbus_asv_add_uint32 (&arr_iter, "OutgoingMessages", out_messages) ||
193 !_dbus_asv_add_uint32 (&arr_iter, "OutgoingBytes", out_bytes) ||
194 !_dbus_asv_add_uint32 (&arr_iter, "OutgoingFDs", out_fds) ||
195 !_dbus_asv_add_uint32 (&arr_iter, "PeakOutgoingBytes", out_peak_bytes) ||
196 !_dbus_asv_add_uint32 (&arr_iter, "PeakOutgoingFDs", out_peak_fds))
197 {
198 _dbus_asv_abandon (&iter, &arr_iter);
199 goto oom;
200 }
201
202 /* end */
203
204 if (!_dbus_asv_close (&iter, &arr_iter))
205 goto oom;
206
207 if (!bus_transaction_send_from_driver (transaction, caller_connection,
208 reply))
209 goto oom;
210
211 dbus_message_unref (reply);
212 return TRUE;
213
214 oom:
215 BUS_SET_OOM (error);
216 /* fall through */
217 failed:
218 if (reply != NULL)
219 dbus_message_unref (reply);
220
221 return FALSE;
222 }
223
224
225 dbus_bool_t
bus_stats_handle_get_all_match_rules(DBusConnection * caller_connection,BusTransaction * transaction,DBusMessage * message,DBusError * error)226 bus_stats_handle_get_all_match_rules (DBusConnection *caller_connection,
227 BusTransaction *transaction,
228 DBusMessage *message,
229 DBusError *error)
230 {
231 BusContext *context;
232 DBusString bus_name_str;
233 DBusMessage *reply = NULL;
234 DBusMessageIter iter, hash_iter, entry_iter, arr_iter;
235 BusRegistry *registry;
236 char **services = NULL;
237 int services_len;
238 DBusConnection *conn_filter = NULL;
239 BusMatchmaker *matchmaker;
240 int i;
241
242 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
243
244 registry = bus_connection_get_registry (caller_connection);
245 context = bus_transaction_get_context (transaction);
246 matchmaker = bus_context_get_matchmaker (context);
247
248 if (!bus_registry_list_services (registry, &services, &services_len))
249 return FALSE;
250
251 reply = dbus_message_new_method_return (message);
252 if (reply == NULL)
253 goto oom;
254
255 dbus_message_iter_init_append (reply, &iter);
256
257 if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sas}",
258 &hash_iter))
259 goto oom;
260
261 for (i = 0 ; i < services_len ; i++)
262 {
263 BusService *service;
264
265 /* To avoid duplicate entries, only look for unique names */
266 if (services[i][0] != ':')
267 continue;
268
269 _dbus_string_init_const (&bus_name_str, services[i]);
270 service = bus_registry_lookup (registry, &bus_name_str);
271 _dbus_assert (service != NULL);
272
273 conn_filter = bus_service_get_primary_owners_connection (service);
274 _dbus_assert (conn_filter != NULL);
275
276 if (!dbus_message_iter_open_container (&hash_iter, DBUS_TYPE_DICT_ENTRY, NULL,
277 &entry_iter))
278 {
279 dbus_message_iter_abandon_container (&iter, &hash_iter);
280 goto oom;
281 }
282
283 if (!dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING, &services[i]))
284 {
285 dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
286 dbus_message_iter_abandon_container (&iter, &hash_iter);
287 goto oom;
288 }
289
290 if (!dbus_message_iter_open_container (&entry_iter, DBUS_TYPE_ARRAY, "s",
291 &arr_iter))
292 {
293 dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
294 dbus_message_iter_abandon_container (&iter, &hash_iter);
295 goto oom;
296 }
297
298 if (!bus_match_rule_dump (matchmaker, conn_filter, &arr_iter))
299 {
300 dbus_message_iter_abandon_container (&entry_iter, &arr_iter);
301 dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
302 dbus_message_iter_abandon_container (&iter, &hash_iter);
303 goto oom;
304 }
305
306 if (!dbus_message_iter_close_container (&entry_iter, &arr_iter))
307 {
308 dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
309 dbus_message_iter_abandon_container (&iter, &hash_iter);
310 goto oom;
311 }
312 if (!dbus_message_iter_close_container (&hash_iter, &entry_iter))
313 {
314 dbus_message_iter_abandon_container (&iter, &hash_iter);
315 goto oom;
316 }
317 }
318
319 if (!dbus_message_iter_close_container (&iter, &hash_iter))
320 goto oom;
321
322 if (!bus_transaction_send_from_driver (transaction, caller_connection,
323 reply))
324 goto oom;
325
326 dbus_message_unref (reply);
327 dbus_free_string_array (services);
328 return TRUE;
329
330 oom:
331 if (reply != NULL)
332 dbus_message_unref (reply);
333
334 dbus_free_string_array (services);
335
336 BUS_SET_OOM (error);
337 return FALSE;
338 }
339
340 #endif
341