2003-03-24 Havoc Pennington <hp@redhat.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   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
188   
189   bd = ensure_bus_data (connection);
190   if (bd == NULL)
191     {
192       _DBUS_SET_OOM (error);
193       return FALSE;
194     }
195
196   if (bd->base_service != NULL)
197     {
198       _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n");
199       /* This isn't an error, it's a programming bug. We'll be nice
200        * and not _dbus_assert_not_reached()
201        */
202       return TRUE;
203     }
204   
205   message = dbus_message_new (DBUS_SERVICE_DBUS,
206                               DBUS_MESSAGE_HELLO);
207
208   if (!message)
209     {
210       _DBUS_SET_OOM (error);
211       return FALSE;
212     }
213   
214   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
215
216   dbus_message_unref (message);
217   
218   if (reply == NULL)
219     {
220       _DBUS_ASSERT_ERROR_IS_SET (error);
221       return FALSE;
222     }
223
224   if (!dbus_message_get_args (reply, error,
225                               DBUS_TYPE_STRING, &name,
226                               0))
227     {
228       _DBUS_ASSERT_ERROR_IS_SET (error);
229       return FALSE;
230     }
231
232   bd->base_service = name;
233   
234   return TRUE;
235 }
236
237
238 /**
239  * Sets the base service name of the connection.
240  * Can only be used if you registered with the
241  * bus manually (i.e. if you did not call
242  * dbus_bus_register()). Can only be called
243  * once per connection.
244  *
245  * @param connection the connection
246  * @param base_service the base service name
247  * @returns #FALSE if not enough memory
248  */
249 dbus_bool_t
250 dbus_bus_set_base_service (DBusConnection *connection,
251                            const char     *base_service)
252 {
253   BusData *bd;
254
255   bd = ensure_bus_data (connection);
256   if (bd == NULL)
257     return FALSE;
258
259   _dbus_assert (bd->base_service == NULL);
260   _dbus_assert (base_service != NULL);
261   
262   bd->base_service = _dbus_strdup (base_service);
263   return bd->base_service != NULL;
264 }
265
266 /**
267  * Gets the base service name of the connection.
268  * Only possible after the connection has been registered
269  * with the message bus.
270  *
271  * @param connection the connection
272  * @returns the base service name
273  */
274 const char*
275 dbus_bus_get_base_service (DBusConnection *connection)
276 {
277   BusData *bd;
278
279   bd = ensure_bus_data (connection);
280   if (bd == NULL)
281     return NULL;
282   
283   return bd->base_service;
284 }
285
286 /**
287  * Asks the bus to try to acquire a certain service.
288  *
289  * @todo these docs are not complete, need to document the
290  * return value and flags
291  * 
292  * @todo if we get an error reply, it has to be converted into
293  * DBusError and returned
294  *
295  * @param connection the connection
296  * @param service_name the service name
297  * @param flags flags
298  * @param error location to store the error
299  * @returns a result code, -1 if error is set
300  */ 
301 int
302 dbus_bus_acquire_service (DBusConnection *connection,
303                           const char     *service_name,
304                           unsigned int    flags,
305                           DBusError      *error)
306 {
307   DBusMessage *message, *reply;
308   int service_result;
309   
310   message = dbus_message_new (DBUS_SERVICE_DBUS,
311                               DBUS_MESSAGE_ACQUIRE_SERVICE);
312
313   if (message == NULL)
314     {
315       _DBUS_SET_OOM (error);
316       return -1;
317     }
318  
319   if (!dbus_message_append_args (message,
320                                  DBUS_TYPE_STRING, service_name,
321                                  DBUS_TYPE_UINT32, flags,
322                                  0))
323     {
324       dbus_message_unref (message);
325       _DBUS_SET_OOM (error);
326       return -1;
327     }
328   
329   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
330                                                      error);
331   
332   dbus_message_unref (message);
333   
334   if (reply == NULL)
335     {
336       _DBUS_ASSERT_ERROR_IS_SET (error);
337       return -1;
338     }
339
340   if (!dbus_message_get_args (reply, error,
341                               DBUS_TYPE_UINT32, &service_result,
342                               0))
343     {
344       _DBUS_ASSERT_ERROR_IS_SET (error);
345       return -1;
346     }
347
348   return service_result;
349 }
350
351 /**
352  * Checks whether a certain service exists.
353  *
354  * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
355  *
356  * @param connection the connection
357  * @param service_name the service name
358  * @param error location to store any errors
359  * @returns #TRUE if the service exists, #FALSE if not or on error
360  */
361 dbus_bool_t
362 dbus_bus_service_exists (DBusConnection *connection,
363                          const char     *service_name,
364                          DBusError      *error)
365 {
366   DBusMessage *message, *reply;
367   unsigned int exists;
368
369   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
370   
371   message = dbus_message_new (DBUS_SERVICE_DBUS,
372                               DBUS_MESSAGE_SERVICE_EXISTS);
373   if (message == NULL)
374     {
375       _DBUS_SET_OOM (error);
376       return FALSE;
377     }
378   
379   if (!dbus_message_append_args (message,
380                                  DBUS_TYPE_STRING, service_name,
381                                  0))
382     {
383       dbus_message_unref (message);
384       _DBUS_SET_OOM (error);
385       return FALSE;
386     }
387   
388   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
389   dbus_message_unref (message);
390
391   if (reply == NULL)
392     {
393       _DBUS_ASSERT_ERROR_IS_SET (error);
394       return FALSE;
395     }
396
397   if (!dbus_message_get_args (reply, error,
398                               DBUS_TYPE_UINT32, &exists,
399                               0))
400     {
401       _DBUS_ASSERT_ERROR_IS_SET (error);
402       return FALSE;
403     }
404   
405   return (exists != FALSE);
406 }
407
408 /** @} */