2003-03-23 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-bus.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-bus.c  Convenience functions for communicating with the bus.
3  *
4  * Copyright (C) 2003  CodeFactory AB
5  * Copyright (C) 2003  Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dbus-bus.h"
26 #include "dbus-protocol.h"
27 #include "dbus-internals.h"
28
29 /**
30  * @defgroup DBusBus Message bus APIs
31  * @ingroup DBus
32  * @brief Functions for communicating with the message bus
33  *
34  */
35
36
37 /**
38  * @defgroup DBusBusInternals Message bus APIs internals
39  * @ingroup DBusInternals
40  * @brief Internals of functions for communicating with the message bus
41  *
42  * @{
43  */
44
45 /**
46  * Block of message-bus-related data we attach to each
47  * #DBusConnection used with these convenience functions.
48  *
49  */
50 typedef struct
51 {
52   char *base_service; /**< Base service name of this connection */
53
54 } BusData;
55
56 /** The slot we have reserved to store BusData
57  */
58 static int bus_data_slot = -1;
59 /** Number of connections using the slot
60  */
61 static int bus_data_slot_refcount = 0;
62
63 /**
64  * Lock for bus_data_slot and bus_data_slot_refcount
65  */
66 _DBUS_DEFINE_GLOBAL_LOCK (bus);
67
68 static dbus_bool_t
69 data_slot_ref (void)
70 {
71   _DBUS_LOCK (bus);
72
73   if (bus_data_slot < 0)
74     {
75       bus_data_slot = dbus_connection_allocate_data_slot ();
76       
77       if (bus_data_slot < 0)
78         {
79           _DBUS_UNLOCK (bus);
80           return FALSE;
81         }
82
83       _dbus_assert (bus_data_slot_refcount == 0);
84     }
85
86   bus_data_slot_refcount += 1;
87
88   _DBUS_UNLOCK (bus);
89
90   return TRUE;
91 }
92
93 static void
94 data_slot_unref (void)
95 {
96   _DBUS_LOCK (bus);
97
98   _dbus_assert (bus_data_slot_refcount > 0);
99   _dbus_assert (bus_data_slot >= 0);
100
101   bus_data_slot_refcount -= 1;
102
103   if (bus_data_slot_refcount == 0)
104     {
105       dbus_connection_free_data_slot (bus_data_slot);
106       bus_data_slot = -1;
107     }
108
109   _DBUS_UNLOCK (bus);
110 }
111
112 static void
113 bus_data_free (void *data)
114 {
115   BusData *bd = data;
116
117   dbus_free (bd->base_service);
118   dbus_free (bd);
119
120   data_slot_unref ();
121 }
122
123 static BusData*
124 ensure_bus_data (DBusConnection *connection)
125 {
126   BusData *bd;
127
128   if (!data_slot_ref ())
129     return NULL;
130
131   bd = dbus_connection_get_data (connection, bus_data_slot);
132   if (bd == NULL)
133     {      
134       bd = dbus_new0 (BusData, 1);
135       if (bd == NULL)
136         {
137           data_slot_unref ();
138           return NULL;
139         }
140       
141       if (!dbus_connection_set_data (connection, bus_data_slot, bd,
142                                      bus_data_free))
143         {
144           dbus_free (bd);
145           data_slot_unref ();
146           return NULL;
147         }
148
149       /* Data slot refcount now held by the BusData */
150     }
151   else
152     {
153       data_slot_unref ();
154     }
155
156   return bd;
157 }
158
159 /** @} */ /* end of implementation details docs */
160
161 /**
162  * @addtogroup DBusBus
163  * @{
164  */
165
166 /**
167  * Registers a connection with the bus. This must be the first
168  * thing an application does when connecting to the message bus.
169  * If registration succeeds, the base service name will be set,
170  * and can be obtained using dbus_bus_get_base_service().
171  *
172  * @todo if we get an error reply, it has to be converted into
173  * DBusError and returned
174  * 
175  * @param connection the connection
176  * @param error place to store errors
177  * @returns #TRUE on success
178  */
179 dbus_bool_t
180 dbus_bus_register (DBusConnection *connection,
181                    DBusError      *error)
182 {
183   DBusMessage *message, *reply;
184   char *name;
185   BusData *bd;
186
187   bd = ensure_bus_data (connection);
188   if (bd == NULL)
189     {
190       _DBUS_SET_OOM (error);
191       return FALSE;
192     }
193
194   if (bd->base_service != NULL)
195     {
196       _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n");
197       /* This isn't an error, it's a programming bug. We'll be nice
198        * and not _dbus_assert_not_reached()
199        */
200       return TRUE;
201     }
202   
203   message = dbus_message_new (DBUS_SERVICE_DBUS,
204                               DBUS_MESSAGE_HELLO);
205
206   if (!message)
207     {
208       _DBUS_SET_OOM (error);
209       return FALSE;
210     }
211   
212   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
213
214   dbus_message_unref (message);
215   
216   if (reply == NULL)
217     {
218       _DBUS_ASSERT_ERROR_IS_SET (error);
219       return FALSE;
220     }
221
222   if (!dbus_message_get_args (reply, error,
223                               DBUS_TYPE_STRING, &name,
224                               0))
225     {
226       _DBUS_ASSERT_ERROR_IS_SET (error);
227       return FALSE;
228     }
229
230   bd->base_service = name;
231   
232   return TRUE;
233 }
234
235
236 /**
237  * Sets the base service name of the connection.
238  * Can only be used if you registered with the
239  * bus manually (i.e. if you did not call
240  * dbus_bus_register()). Can only be called
241  * once per connection.
242  *
243  * @param connection the connection
244  * @param base_service the base service name
245  * @returns #FALSE if not enough memory
246  */
247 dbus_bool_t
248 dbus_bus_set_base_service (DBusConnection *connection,
249                            const char     *base_service)
250 {
251   BusData *bd;
252
253   bd = ensure_bus_data (connection);
254   if (bd == NULL)
255     return FALSE;
256
257   _dbus_assert (bd->base_service == NULL);
258   _dbus_assert (base_service != NULL);
259   
260   bd->base_service = _dbus_strdup (base_service);
261   return bd->base_service != NULL;
262 }
263
264 /**
265  * Gets the base service name of the connection.
266  * Only possible after the connection has been registered
267  * with the message bus.
268  *
269  * @param connection the connection
270  * @returns the base service name
271  */
272 const char*
273 dbus_bus_get_base_service (DBusConnection *connection)
274 {
275   BusData *bd;
276
277   bd = ensure_bus_data (connection);
278   if (bd == NULL)
279     return NULL;
280   
281   return bd->base_service;
282 }
283
284 /**
285  * Asks the bus to try to acquire a certain service.
286  *
287  * @todo these docs are not complete, need to document the
288  * return value and flags
289  * 
290  * @todo if we get an error reply, it has to be converted into
291  * DBusError and returned
292  *
293  * @param connection the connection
294  * @param service_name the service name
295  * @param flags flags
296  * @param error location to store the error
297  * @returns a result code, -1 if error is set
298  */ 
299 int
300 dbus_bus_acquire_service (DBusConnection *connection,
301                           const char     *service_name,
302                           unsigned int    flags,
303                           DBusError      *error)
304 {
305   DBusMessage *message, *reply;
306   int service_result;
307   
308   message = dbus_message_new (DBUS_SERVICE_DBUS,
309                               DBUS_MESSAGE_ACQUIRE_SERVICE);
310
311   if (message == NULL)
312     {
313       _DBUS_SET_OOM (error);
314       return -1;
315     }
316  
317   if (!dbus_message_append_args (message,
318                                  DBUS_TYPE_STRING, service_name,
319                                  DBUS_TYPE_UINT32, flags,
320                                  0))
321     {
322       dbus_message_unref (message);
323       _DBUS_SET_OOM (error);
324       return -1;
325     }
326   
327   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
328                                                      error);
329   
330   dbus_message_unref (message);
331   
332   if (reply == NULL)
333     {
334       _DBUS_ASSERT_ERROR_IS_SET (error);
335       return -1;
336     }
337
338   if (!dbus_message_get_args (reply, error,
339                               DBUS_TYPE_UINT32, &service_result,
340                               0))
341     {
342       _DBUS_ASSERT_ERROR_IS_SET (error);
343       return -1;
344     }
345
346   return service_result;
347 }
348
349 /**
350  * Checks whether a certain service exists.
351  *
352  * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
353  *
354  * @param connection the connection
355  * @param service_name the service name
356  * @param error location to store any errors
357  * @returns #TRUE if the service exists, #FALSE if not or on error
358  */
359 dbus_bool_t
360 dbus_bus_service_exists (DBusConnection *connection,
361                          const char     *service_name,
362                          DBusError      *error)
363 {
364   DBusMessage *message, *reply;
365   unsigned int exists;
366   
367   message = dbus_message_new (DBUS_SERVICE_DBUS,
368                               DBUS_MESSAGE_SERVICE_EXISTS);
369   if (message == NULL)
370     {
371       _DBUS_SET_OOM (error);
372       return FALSE;
373     }
374   
375   if (!dbus_message_append_args (message,
376                                  DBUS_TYPE_STRING, service_name,
377                                  0))
378     {
379       dbus_message_unref (message);
380       _DBUS_SET_OOM (error);
381       return FALSE;
382     }
383   
384   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
385   dbus_message_unref (message);
386
387   if (reply == NULL)
388     {
389       _DBUS_ASSERT_ERROR_IS_SET (error);
390       return FALSE;
391     }
392
393   if (!dbus_message_get_args (reply, error,
394                               DBUS_TYPE_UINT32, &exists,
395                               0))
396     {
397       _DBUS_ASSERT_ERROR_IS_SET (error);
398       return FALSE;
399     }
400   
401   return (exists != FALSE);
402 }
403
404 /** @} */