patch: bus: Fix timeout restarts
[platform/upstream/dbus.git] / bus / stats.c
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 BusResult
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   if (!bus_driver_check_message_is_for_us (message, error))
55     return FALSE;
56
57   context = bus_transaction_get_context (transaction);
58   connections = bus_context_get_connections (context);
59
60   reply = _dbus_asv_new_method_return (message, &iter, &arr_iter);
61
62   if (reply == NULL)
63     goto oom;
64
65   /* Globals */
66
67   _dbus_list_get_stats (&in_use, &in_free_list, &allocated);
68
69   if (!_dbus_asv_add_uint32 (&arr_iter, "Serial", stats_serial++) ||
70       !_dbus_asv_add_uint32 (&arr_iter, "ListMemPoolUsedBytes", in_use) ||
71       !_dbus_asv_add_uint32 (&arr_iter, "ListMemPoolCachedBytes", in_free_list) ||
72       !_dbus_asv_add_uint32 (&arr_iter, "ListMemPoolAllocatedBytes", allocated))
73     {
74       _dbus_asv_abandon (&iter, &arr_iter);
75       goto oom;
76     }
77
78   /* Connections */
79
80   if (!_dbus_asv_add_uint32 (&arr_iter, "ActiveConnections",
81         bus_connections_get_n_active (connections)) ||
82       !_dbus_asv_add_uint32 (&arr_iter, "IncompleteConnections",
83         bus_connections_get_n_incomplete (connections)) ||
84       !_dbus_asv_add_uint32 (&arr_iter, "MatchRules",
85         bus_connections_get_total_match_rules (connections)) ||
86       !_dbus_asv_add_uint32 (&arr_iter, "PeakMatchRules",
87         bus_connections_get_peak_match_rules (connections)) ||
88       !_dbus_asv_add_uint32 (&arr_iter, "PeakMatchRulesPerConnection",
89         bus_connections_get_peak_match_rules_per_conn (connections)) ||
90       !_dbus_asv_add_uint32 (&arr_iter, "BusNames",
91         bus_connections_get_total_bus_names (connections)) ||
92       !_dbus_asv_add_uint32 (&arr_iter, "PeakBusNames",
93         bus_connections_get_peak_bus_names (connections)) ||
94       !_dbus_asv_add_uint32 (&arr_iter, "PeakBusNamesPerConnection",
95         bus_connections_get_peak_bus_names_per_conn (connections)))
96     {
97       _dbus_asv_abandon (&iter, &arr_iter);
98       goto oom;
99     }
100
101   /* end */
102
103   if (!_dbus_asv_close (&iter, &arr_iter))
104     goto oom;
105
106   if (!bus_transaction_send_from_driver (transaction, connection, reply))
107     goto oom;
108
109   dbus_message_unref (reply);
110   return BUS_RESULT_TRUE;
111
112 oom:
113   if (reply != NULL)
114     dbus_message_unref (reply);
115
116   BUS_SET_OOM (error);
117   return BUS_RESULT_FALSE;
118 }
119
120 BusResult
121 bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
122                                        BusTransaction *transaction,
123                                        DBusMessage    *message,
124                                        DBusError      *error)
125 {
126   const char *bus_name = NULL;
127   DBusString bus_name_str;
128   DBusMessage *reply = NULL;
129   DBusMessageIter iter, arr_iter;
130   static dbus_uint32_t stats_serial = 0;
131   dbus_uint32_t in_messages, in_bytes, in_fds, in_peak_bytes, in_peak_fds;
132   dbus_uint32_t out_messages, out_bytes, out_fds, out_peak_bytes, out_peak_fds;
133   BusRegistry *registry;
134   BusService *service;
135   DBusConnection *stats_connection;
136
137   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
138
139   if (!bus_driver_check_message_is_for_us (message, error))
140     return FALSE;
141
142   registry = bus_connection_get_registry (caller_connection);
143
144   if (! dbus_message_get_args (message, error,
145                                DBUS_TYPE_STRING, &bus_name,
146                                DBUS_TYPE_INVALID))
147       return BUS_RESULT_FALSE;
148
149   _dbus_string_init_const (&bus_name_str, bus_name);
150   service = bus_registry_lookup (registry, &bus_name_str);
151
152   if (service == NULL)
153     {
154       dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
155                       "Bus name '%s' has no owner", bus_name);
156       return BUS_RESULT_FALSE;
157     }
158
159   stats_connection = bus_service_get_primary_owners_connection (service);
160   _dbus_assert (stats_connection != NULL);
161
162   reply = _dbus_asv_new_method_return (message, &iter, &arr_iter);
163
164   if (reply == NULL)
165     goto oom;
166
167   /* Bus daemon per-connection stats */
168
169   if (!_dbus_asv_add_uint32 (&arr_iter, "Serial", stats_serial++) ||
170       !_dbus_asv_add_uint32 (&arr_iter, "MatchRules",
171         bus_connection_get_n_match_rules (stats_connection)) ||
172       !_dbus_asv_add_uint32 (&arr_iter, "PeakMatchRules",
173         bus_connection_get_peak_match_rules (stats_connection)) ||
174       !_dbus_asv_add_uint32 (&arr_iter, "BusNames",
175         bus_connection_get_n_services_owned (stats_connection)) ||
176       !_dbus_asv_add_uint32 (&arr_iter, "PeakBusNames",
177         bus_connection_get_peak_bus_names (stats_connection)) ||
178       !_dbus_asv_add_string (&arr_iter, "UniqueName",
179         bus_connection_get_name (stats_connection)))
180     {
181       _dbus_asv_abandon (&iter, &arr_iter);
182       goto oom;
183     }
184
185   /* DBusConnection per-connection stats */
186
187   _dbus_connection_get_stats (stats_connection,
188                               &in_messages, &in_bytes, &in_fds,
189                               &in_peak_bytes, &in_peak_fds,
190                               &out_messages, &out_bytes, &out_fds,
191                               &out_peak_bytes, &out_peak_fds);
192
193   if (!_dbus_asv_add_uint32 (&arr_iter, "IncomingMessages", in_messages) ||
194       !_dbus_asv_add_uint32 (&arr_iter, "IncomingBytes", in_bytes) ||
195       !_dbus_asv_add_uint32 (&arr_iter, "IncomingFDs", in_fds) ||
196       !_dbus_asv_add_uint32 (&arr_iter, "PeakIncomingBytes", in_peak_bytes) ||
197       !_dbus_asv_add_uint32 (&arr_iter, "PeakIncomingFDs", in_peak_fds) ||
198       !_dbus_asv_add_uint32 (&arr_iter, "OutgoingMessages", out_messages) ||
199       !_dbus_asv_add_uint32 (&arr_iter, "OutgoingBytes", out_bytes) ||
200       !_dbus_asv_add_uint32 (&arr_iter, "OutgoingFDs", out_fds) ||
201       !_dbus_asv_add_uint32 (&arr_iter, "PeakOutgoingBytes", out_peak_bytes) ||
202       !_dbus_asv_add_uint32 (&arr_iter, "PeakOutgoingFDs", out_peak_fds))
203     {
204       _dbus_asv_abandon (&iter, &arr_iter);
205       goto oom;
206     }
207
208   /* end */
209
210   if (!_dbus_asv_close (&iter, &arr_iter))
211     goto oom;
212
213   if (!bus_transaction_send_from_driver (transaction, caller_connection,
214                                          reply))
215     goto oom;
216
217   dbus_message_unref (reply);
218   return BUS_RESULT_TRUE;
219
220 oom:
221   if (reply != NULL)
222     dbus_message_unref (reply);
223
224   BUS_SET_OOM (error);
225   return BUS_RESULT_FALSE;
226 }
227
228
229 dbus_bool_t
230 bus_stats_handle_get_all_match_rules (DBusConnection *caller_connection,
231                                       BusTransaction *transaction,
232                                       DBusMessage    *message,
233                                       DBusError      *error)
234 {
235   BusContext *context;
236   DBusString bus_name_str;
237   DBusMessage *reply = NULL;
238   DBusMessageIter iter, hash_iter, entry_iter, arr_iter;
239   BusRegistry *registry;
240   char **services = NULL;
241   int services_len;
242   DBusConnection *conn_filter = NULL;
243   BusMatchmaker *matchmaker;
244   int i;
245
246   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
247
248   registry = bus_connection_get_registry (caller_connection);
249   context = bus_transaction_get_context (transaction);
250   matchmaker = bus_context_get_matchmaker (context);
251
252   if (!bus_registry_list_services (registry, &services, &services_len))
253     return FALSE;
254
255   reply = dbus_message_new_method_return (message);
256   if (reply == NULL)
257     goto oom;
258
259   dbus_message_iter_init_append (reply, &iter);
260
261   if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sas}",
262                                          &hash_iter))
263     goto oom;
264
265   for (i = 0 ; i < services_len ; i++)
266     {
267       BusService *service;
268
269       /* To avoid duplicate entries, only look for unique names */
270       if (services[i][0] != ':')
271         continue;
272
273       _dbus_string_init_const (&bus_name_str, services[i]);
274       service = bus_registry_lookup (registry, &bus_name_str);
275       _dbus_assert (service != NULL);
276
277       conn_filter = bus_service_get_primary_owners_connection (service);
278       _dbus_assert (conn_filter != NULL);
279
280       if (!dbus_message_iter_open_container (&hash_iter, DBUS_TYPE_DICT_ENTRY, NULL,
281                                              &entry_iter))
282         {
283           dbus_message_iter_abandon_container (&iter, &hash_iter);
284           goto oom;
285         }
286
287       if (!dbus_message_iter_append_basic (&entry_iter, DBUS_TYPE_STRING, &services[i]))
288         {
289           dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
290           dbus_message_iter_abandon_container (&iter, &hash_iter);
291           goto oom;
292         }
293
294       if (!dbus_message_iter_open_container (&entry_iter, DBUS_TYPE_ARRAY, "s",
295                                              &arr_iter))
296         {
297           dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
298           dbus_message_iter_abandon_container (&iter, &hash_iter);
299           goto oom;
300         }
301
302       if (!bus_match_rule_dump (matchmaker, conn_filter, &arr_iter))
303         {
304           dbus_message_iter_abandon_container (&entry_iter, &arr_iter);
305           dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
306           dbus_message_iter_abandon_container (&iter, &hash_iter);
307           goto oom;
308         }
309
310       if (!dbus_message_iter_close_container (&entry_iter, &arr_iter))
311         {
312           dbus_message_iter_abandon_container (&hash_iter, &entry_iter);
313           dbus_message_iter_abandon_container (&iter, &hash_iter);
314           goto oom;
315         }
316       if (!dbus_message_iter_close_container (&hash_iter, &entry_iter))
317         {
318           dbus_message_iter_abandon_container (&iter, &hash_iter);
319           goto oom;
320         }
321     }
322
323   if (!dbus_message_iter_close_container (&iter, &hash_iter))
324     goto oom;
325
326   if (!bus_transaction_send_from_driver (transaction, caller_connection,
327                                          reply))
328     goto oom;
329
330   dbus_message_unref (reply);
331   dbus_free_string_array (services);
332   return TRUE;
333
334 oom:
335   if (reply != NULL)
336     dbus_message_unref (reply);
337
338   dbus_free_string_array (services);
339
340   BUS_SET_OOM (error);
341   return FALSE;
342 }
343
344 #endif