Add a stub .Debug.Stats interface if --enable-stats
[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
191   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
192
193   connections = bus_transaction_get_connections (transaction);
194
195   reply = new_asv_reply (message, &iter, &arr_iter);
196
197   if (reply == NULL)
198     goto oom;
199
200   if (!asv_add_uint32 (&iter, &arr_iter, "Serial", stats_serial++))
201     goto oom;
202
203   if (!close_asv_reply (&iter, &arr_iter))
204     goto oom;
205
206   if (!bus_transaction_send_from_driver (transaction, connection, reply))
207     goto oom;
208
209   dbus_message_unref (reply);
210   return TRUE;
211
212 oom:
213   if (reply != NULL)
214     dbus_message_unref (reply);
215
216   BUS_SET_OOM (error);
217   return FALSE;
218 }
219
220 dbus_bool_t
221 bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
222                                        BusTransaction *transaction,
223                                        DBusMessage    *message,
224                                        DBusError      *error)
225 {
226   const char *bus_name = NULL;
227   DBusString bus_name_str;
228   DBusMessage *reply = NULL;
229   DBusMessageIter iter, arr_iter;
230   static dbus_uint32_t stats_serial = 0;
231   dbus_uint32_t in_messages, in_bytes, in_fds;
232   dbus_uint32_t out_messages, out_bytes, out_fds;
233   BusRegistry *registry;
234   BusService *service;
235   DBusConnection *stats_connection;
236
237   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
238
239   registry = bus_connection_get_registry (caller_connection);
240
241   if (! dbus_message_get_args (message, error,
242                                DBUS_TYPE_STRING, &bus_name,
243                                DBUS_TYPE_INVALID))
244       return FALSE;
245
246   _dbus_string_init_const (&bus_name_str, bus_name);
247   service = bus_registry_lookup (registry, &bus_name_str);
248
249   if (service == NULL)
250     {
251       dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
252                       "Bus name '%s' has no owner", bus_name);
253       return FALSE;
254     }
255
256   stats_connection = bus_service_get_primary_owners_connection (service);
257   _dbus_assert (stats_connection != NULL);
258
259   reply = new_asv_reply (message, &iter, &arr_iter);
260
261   if (reply == NULL)
262     goto oom;
263
264   if (!asv_add_uint32 (&iter, &arr_iter, "Serial", stats_serial++) ||
265       !asv_add_string (&iter, &arr_iter, "UniqueName",
266         bus_connection_get_name (stats_connection)))
267     goto oom;
268
269   if (!close_asv_reply (&iter, &arr_iter))
270     goto oom;
271
272   if (!bus_transaction_send_from_driver (transaction, caller_connection,
273                                          reply))
274     goto oom;
275
276   dbus_message_unref (reply);
277   return TRUE;
278
279 oom:
280   if (reply != NULL)
281     dbus_message_unref (reply);
282
283   BUS_SET_OOM (error);
284   return FALSE;
285 }
286
287 #endif