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