• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
new_asv_reply(DBusMessage * message,DBusMessageIter * iter,DBusMessageIter * arr_iter)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
open_asv_entry(DBusMessageIter * arr_iter,DBusMessageIter * entry_iter,const char * key,const char * type,DBusMessageIter * var_iter)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
close_asv_entry(DBusMessageIter * arr_iter,DBusMessageIter * entry_iter,DBusMessageIter * var_iter)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
close_asv_reply(DBusMessageIter * iter,DBusMessageIter * arr_iter)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
abandon_asv_entry(DBusMessageIter * arr_iter,DBusMessageIter * entry_iter,DBusMessageIter * var_iter)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
abandon_asv_reply(DBusMessageIter * iter,DBusMessageIter * arr_iter)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
asv_add_uint32(DBusMessageIter * iter,DBusMessageIter * arr_iter,const char * key,dbus_uint32_t value)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
asv_add_string(DBusMessageIter * iter,DBusMessageIter * arr_iter,const char * key,const char * value)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
bus_stats_handle_get_stats(DBusConnection * connection,BusTransaction * transaction,DBusMessage * message,DBusError * error)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
bus_stats_handle_get_connection_stats(DBusConnection * caller_connection,BusTransaction * transaction,DBusMessage * message,DBusError * error)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