2003-03-16 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 static DBusMutex *slot_lock;
67
68 /**
69  * Initialize the mutex used for bus_data_slot
70  *
71  * @returns the mutex
72  */
73 DBusMutex *
74 _dbus_bus_init_lock (void)
75 {
76   slot_lock = dbus_mutex_new ();
77   return slot_lock;
78 }
79
80 static dbus_bool_t
81 data_slot_ref (void)
82 {
83   dbus_mutex_lock (slot_lock);
84
85   if (bus_data_slot < 0)
86     bus_data_slot = dbus_connection_allocate_data_slot ();
87
88   if (bus_data_slot < 0)
89     {
90       dbus_mutex_unlock (slot_lock);
91       return FALSE;
92     }
93
94   bus_data_slot_refcount += 1;
95
96   dbus_mutex_unlock (slot_lock);
97
98   return TRUE;
99 }
100
101 static void
102 data_slot_unref (void)
103 {
104   dbus_mutex_lock (slot_lock);
105
106   _dbus_assert (bus_data_slot >= 0);
107   _dbus_assert (bus_data_slot_refcount > 0);
108
109   bus_data_slot_refcount -= 1;
110
111   if (bus_data_slot_refcount == 0)
112     {
113       dbus_connection_free_data_slot (bus_data_slot);
114       bus_data_slot = -1;
115     }
116
117   dbus_mutex_unlock (slot_lock);
118 }
119
120 static void
121 bus_data_free (void *data)
122 {
123   BusData *bd = data;
124
125   dbus_free (bd->base_service);
126   dbus_free (bd);
127
128   data_slot_unref ();
129 }
130
131 static BusData*
132 ensure_bus_data (DBusConnection *connection)
133 {
134   BusData *bd;
135
136   if (!data_slot_ref ())
137     return NULL;
138
139   bd = dbus_connection_get_data (connection, bus_data_slot);
140   if (bd == NULL)
141     {      
142       bd = dbus_new0 (BusData, 1);
143       if (bd == NULL)
144         {
145           data_slot_unref ();
146           return NULL;
147         }
148       
149       if (!dbus_connection_set_data (connection, bus_data_slot, bd,
150                                      bus_data_free))
151         {
152           bus_data_free (bd);
153           data_slot_unref ();
154           return NULL;
155         }
156
157       /* Data slot refcount now held by the BusData */
158     }
159   else
160     {
161       data_slot_unref ();
162     }
163
164   return bd;
165 }
166
167 /** @} */ /* end of implementation details docs */
168
169 /**
170  * @addtogroup DBusBus
171  * @{
172  */
173
174 /**
175  * Registers a connection with the bus. This must be the first
176  * thing an application does when connecting to the message bus.
177  * If registration succeeds, the base service name will be set,
178  * and can be obtained using dbus_bus_get_base_service().
179  *
180  * @todo if we get an error reply, it has to be converted into
181  * DBusError and returned
182  * 
183  * @param connection the connection
184  * @param error place to store errors
185  * @returns #TRUE on success
186  */
187 dbus_bool_t
188 dbus_bus_register (DBusConnection *connection,
189                    DBusError      *error)
190 {
191   DBusMessage *message, *reply;
192   char *name;
193   BusData *bd;
194
195   bd = ensure_bus_data (connection);
196   if (bd == NULL)
197     {
198       _DBUS_SET_OOM (error);
199       return FALSE;
200     }
201
202   if (bd->base_service != NULL)
203     {
204       _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n");
205       /* This isn't an error, it's a programming bug. We'll be nice
206        * and not _dbus_assert_not_reached()
207        */
208       return TRUE;
209     }
210   
211   message = dbus_message_new (DBUS_SERVICE_DBUS,
212                               DBUS_MESSAGE_HELLO);
213
214   if (!message)
215     {
216       _DBUS_SET_OOM (error);
217       return FALSE;
218     }
219   
220   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
221
222   dbus_message_unref (message);
223   
224   if (reply == NULL)
225     {
226       _DBUS_ASSERT_ERROR_IS_SET (error);
227       return FALSE;
228     }
229
230   if (!dbus_message_get_args (reply, error,
231                               DBUS_TYPE_STRING, &name,
232                               0))
233     {
234       _DBUS_ASSERT_ERROR_IS_SET (error);
235       return FALSE;
236     }
237
238   bd->base_service = name;
239   
240   return TRUE;
241 }
242
243
244 /**
245  * Sets the base service name of the connection.
246  * Can only be used if you registered with the
247  * bus manually (i.e. if you did not call
248  * dbus_bus_register()). Can only be called
249  * once per connection.
250  *
251  * @param connection the connection
252  * @param base_service the base service name
253  * @returns #FALSE if not enough memory
254  */
255 dbus_bool_t
256 dbus_bus_set_base_service (DBusConnection *connection,
257                            const char     *base_service)
258 {
259   BusData *bd;
260
261   bd = ensure_bus_data (connection);
262   if (bd == NULL)
263     return FALSE;
264
265   _dbus_assert (bd->base_service == NULL);
266   _dbus_assert (base_service != NULL);
267   
268   bd->base_service = _dbus_strdup (base_service);
269   return bd->base_service != NULL;
270 }
271
272 /**
273  * Gets the base service name of the connection.
274  * Only possible after the connection has been registered
275  * with the message bus.
276  *
277  * @param connection the connection
278  * @returns the base service name
279  */
280 const char*
281 dbus_bus_get_base_service (DBusConnection *connection)
282 {
283   BusData *bd;
284
285   bd = ensure_bus_data (connection);
286   if (bd == NULL)
287     return NULL;
288   
289   return bd->base_service;
290 }
291
292 /**
293  * Asks the bus to try to acquire a certain service.
294  *
295  * @todo these docs are not complete, need to document the
296  * return value and flags
297  * 
298  * @todo if we get an error reply, it has to be converted into
299  * DBusError and returned
300  *
301  * @param connection the connection
302  * @param service_name the service name
303  * @param flags flags
304  * @param error location to store the error
305  * @returns a result code, -1 if error is set
306  */ 
307 int
308 dbus_bus_acquire_service (DBusConnection *connection,
309                           const char     *service_name,
310                           unsigned int    flags,
311                           DBusError      *error)
312 {
313   DBusMessage *message, *reply;
314   int service_result;
315   
316   message = dbus_message_new (DBUS_SERVICE_DBUS,
317                               DBUS_MESSAGE_ACQUIRE_SERVICE);
318
319   if (message == NULL)
320     {
321       _DBUS_SET_OOM (error);
322       return -1;
323     }
324  
325   if (!dbus_message_append_args (message,
326                                  DBUS_TYPE_STRING, service_name,
327                                  DBUS_TYPE_UINT32, flags,
328                                  0))
329     {
330       dbus_message_unref (message);
331       _DBUS_SET_OOM (error);
332       return -1;
333     }
334   
335   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
336                                                      error);
337   
338   dbus_message_unref (message);
339   
340   if (reply == NULL)
341     {
342       _DBUS_ASSERT_ERROR_IS_SET (error);
343       return -1;
344     }
345
346   if (!dbus_message_get_args (reply, error,
347                               DBUS_TYPE_UINT32, &service_result,
348                               0))
349     {
350       _DBUS_ASSERT_ERROR_IS_SET (error);
351       return -1;
352     }
353
354   return service_result;
355 }
356
357 /**
358  * Checks whether a certain service exists.
359  *
360  * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
361  *
362  * @param connection the connection
363  * @param service_name the service name
364  * @param error location to store any errors
365  * @returns #TRUE if the service exists, #FALSE if not or on error
366  */
367 dbus_bool_t
368 dbus_bus_service_exists (DBusConnection *connection,
369                          const char     *service_name,
370                          DBusError      *error)
371 {
372   DBusMessage *message, *reply;
373   unsigned int exists;
374   
375   message = dbus_message_new (DBUS_SERVICE_DBUS,
376                               DBUS_MESSAGE_SERVICE_EXISTS);
377   if (message == NULL)
378     {
379       _DBUS_SET_OOM (error);
380       return FALSE;
381     }
382   
383   if (!dbus_message_append_args (message,
384                                  DBUS_TYPE_STRING, service_name,
385                                  0))
386     {
387       dbus_message_unref (message);
388       _DBUS_SET_OOM (error);
389       return FALSE;
390     }
391   
392   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
393   dbus_message_unref (message);
394
395   if (reply == NULL)
396     {
397       _DBUS_ASSERT_ERROR_IS_SET (error);
398       return FALSE;
399     }
400
401   if (!dbus_message_get_args (reply, error,
402                               DBUS_TYPE_UINT32, &exists,
403                               0))
404     {
405       _DBUS_ASSERT_ERROR_IS_SET (error);
406       return FALSE;
407     }
408   
409   return (exists != FALSE);
410 }
411
412 /** @} */