bus: Assign a serial number for messages from the driver
[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   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 BUS_RESULT_TRUE;
108
109 oom:
110   if (reply != NULL)
111     dbus_message_unref (reply);
112
113   BUS_SET_OOM (error);
114   return BUS_RESULT_FALSE;
115 }
116
117 BusResult
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       !_dbus_asv_add_uint32 (&arr_iter, "PendingReplies",
175         bus_connection_get_n_pending_replies (stats_connection)) ||
176       !_dbus_asv_add_uint32 (&arr_iter, "PeakPendingReplies",
177         bus_connection_get_peak_pending_replies (stats_connection)))
178     {
179       _dbus_asv_abandon (&iter, &arr_iter);
180       goto oom;
181     }
182
183   /* DBusConnection per-connection stats */
184
185   _dbus_connection_get_stats (stats_connection,
186                               &in_messages, &in_bytes, &in_fds,
187                               &in_peak_bytes, &in_peak_fds,
188                               &out_messages, &out_bytes, &out_fds,
189                               &out_peak_bytes, &out_peak_fds);
190
191   if (!_dbus_asv_add_uint32 (&arr_iter, "IncomingMessages", in_messages) ||
192       !_dbus_asv_add_uint32 (&arr_iter, "IncomingBytes", in_bytes) ||
193       !_dbus_asv_add_uint32 (&arr_iter, "IncomingFDs", in_fds) ||
194       !_dbus_asv_add_uint32 (&arr_iter, "PeakIncomingBytes", in_peak_bytes) ||
195       !_dbus_asv_add_uint32 (&arr_iter, "PeakIncomingFDs", in_peak_fds) ||
196       !_dbus_asv_add_uint32 (&arr_iter, "OutgoingMessages", out_messages) ||
197       !_dbus_asv_add_uint32 (&arr_iter, "OutgoingBytes", out_bytes) ||
198       !_dbus_asv_add_uint32 (&arr_iter, "OutgoingFDs", out_fds) ||
199       !_dbus_asv_add_uint32 (&arr_iter, "PeakOutgoingBytes", out_peak_bytes) ||
200       !_dbus_asv_add_uint32 (&arr_iter, "PeakOutgoingFDs", out_peak_fds))
201     {
202       _dbus_asv_abandon (&iter, &arr_iter);
203       goto oom;
204     }
205
206   /* end */
207
208   if (!_dbus_asv_close (&iter, &arr_iter))
209     goto oom;
210
211   if (!bus_transaction_send_from_driver (transaction, caller_connection,
212                                          reply))
213     goto oom;
214
215   dbus_message_unref (reply);
216   return BUS_RESULT_TRUE;
217
218 oom:
219   BUS_SET_OOM (error);
220   /* fall through */
221 failed:
222   if (reply != NULL)
223     dbus_message_unref (reply);
224
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