4553191063c1000de7450d0176fd52bb0f4bf1bd
[platform/upstream/dbus.git] / bus / stats.c
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   if (!_dbus_list_get_stats (&in_use, &in_free_list, &allocated) ||
207       !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