2003-02-13 Anders Carlsson <andersca@codefactory.se>
[platform/upstream/dbus.git] / bus / services.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* services.c  Service management
3  *
4  * Copyright (C) 2003  Red Hat, Inc.
5  * Copyright (C) 2003  CodeFactory AB
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 #include "driver.h"
25 #include "services.h"
26 #include "connection.h"
27 #include <dbus/dbus-hash.h>
28 #include <dbus/dbus-list.h>
29 #include <dbus/dbus-mempool.h>
30
31 struct BusService
32 {
33   char *name;
34   DBusList *owners;
35
36   unsigned int prohibit_replacement:1;
37 };
38
39 static DBusHashTable *service_hash = NULL;
40 static DBusMemPool   *service_pool = NULL;
41
42 BusService*
43 bus_service_lookup (const DBusString *service_name,
44                     dbus_bool_t       create_if_not_found)
45 {
46   const char *c_name;
47   BusService *service;
48   
49   if (service_hash == NULL)
50     {
51       service_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
52                                            NULL, NULL);
53       service_pool = _dbus_mem_pool_new (sizeof (BusService),
54                                          TRUE);
55
56       if (service_hash == NULL || service_pool == NULL)
57         {
58           if (service_hash)
59             {
60               _dbus_hash_table_unref (service_hash);
61               service_hash = NULL;
62             }
63           if (service_pool)
64             {
65               _dbus_mem_pool_free (service_pool);
66               service_pool = NULL;
67             }
68           return NULL;
69         }
70     }
71   
72   _dbus_string_get_const_data (service_name, &c_name);
73
74   service = _dbus_hash_table_lookup_string (service_hash,
75                                             c_name);
76   if (service != NULL)
77     return service;
78
79   if (!create_if_not_found)
80     return NULL;
81   
82   service = _dbus_mem_pool_alloc (service_pool);
83   if (service == NULL)
84     return NULL;
85
86   service->name = _dbus_strdup (c_name);
87   if (service->name == NULL)
88     {
89       _dbus_mem_pool_dealloc (service_pool, service);
90       return NULL;
91     }
92
93   if (!_dbus_hash_table_insert_string (service_hash,
94                                        service->name,
95                                        service))
96     {
97       dbus_free (service->name);
98       _dbus_mem_pool_dealloc (service_pool, service);
99       return NULL;
100     }
101
102   bus_driver_send_service_created (service->name);
103   
104   return service;
105 }
106
107 dbus_bool_t
108 bus_service_add_owner (BusService     *service,
109                        DBusConnection *owner)
110 {
111   if (!_dbus_list_append (&service->owners,
112                           owner))
113     return FALSE;
114
115   if (!bus_connection_add_owned_service (owner, service))
116     {
117       _dbus_list_remove_last (&service->owners, owner);
118       return FALSE;
119     }
120
121  /* Send service acquired message */
122   if (bus_service_get_primary_owner (service) == owner)
123     bus_driver_send_service_acquired (owner, service->name);
124   
125   return TRUE;
126 }
127
128 void
129 bus_service_remove_owner (BusService     *service,
130                           DBusConnection *owner)
131 {
132   /* Send service lost message */
133   if (bus_service_get_primary_owner (service) == owner)
134     bus_driver_send_service_lost (owner, service->name);
135   
136   _dbus_list_remove_last (&service->owners, owner);
137   bus_connection_remove_owned_service (owner, service);
138
139   if (service->owners == NULL)
140     {
141       /* Delete service */
142       bus_driver_send_service_deleted (service->name);
143       
144       _dbus_hash_table_remove_string (service_hash, service->name);
145       
146       dbus_free (service->name);
147       _dbus_mem_pool_dealloc (service_pool, service);
148     }
149   else 
150     {
151       /* Send service acquired to the new owner */
152       bus_driver_send_service_acquired (bus_service_get_primary_owner (service),
153                                         service->name);
154     }
155 }
156
157 DBusConnection*
158 bus_service_get_primary_owner (BusService *service)
159 {
160   return _dbus_list_get_first (&service->owners);
161 }
162
163 const char*
164 bus_service_get_name (BusService *service)
165 {
166   return service->name;
167 }
168
169 void
170 bus_service_foreach (BusServiceForeachFunction  function,
171                      void                      *data)
172 {
173   DBusHashIter iter;
174   
175   if (service_hash == NULL)
176     return;
177   
178   _dbus_hash_iter_init (service_hash, &iter);
179   while (_dbus_hash_iter_next (&iter))
180     {
181       BusService *service = _dbus_hash_iter_get_value (&iter);
182
183       (* function) (service, data);
184     }
185 }
186
187 char **
188 bus_services_list (int *array_len)
189 {
190   int i, j, len;
191   char **retval;
192   DBusHashIter iter;
193    
194   len = _dbus_hash_table_get_n_entries (service_hash);
195   retval = dbus_new (char *, len);
196
197   if (retval == NULL)
198     return NULL;
199
200   _dbus_hash_iter_init (service_hash, &iter);
201   i = 0;
202   while (_dbus_hash_iter_next (&iter))
203     {
204       BusService *service = _dbus_hash_iter_get_value (&iter);
205
206       retval[i] = _dbus_strdup (service->name);
207       if (retval[i] == NULL)
208         goto error;
209
210       i++;
211     }
212
213   if (array_len)
214     *array_len = len;
215   
216   return retval;
217   
218  error:
219   for (j = 0; j < i; j++)
220     dbus_free (retval[i]);
221   dbus_free (retval);
222
223   return NULL;
224 }
225
226 void
227 bus_service_set_prohibit_replacement (BusService  *service,
228                                       dbus_bool_t  prohibit_replacement)
229 {
230   _dbus_assert (service->owners == NULL);
231   
232   service->prohibit_replacement = prohibit_replacement != FALSE;
233 }
234
235 dbus_bool_t
236 bus_service_get_prohibit_replacement (BusService *service)
237 {
238   return service->prohibit_replacement;
239 }
240
241 dbus_bool_t
242 bus_service_has_owner (BusService     *service,
243                        DBusConnection *owner)
244 {
245   DBusList *link;
246
247   link = _dbus_list_get_first_link (&service->owners);
248   
249   while (link != NULL)
250     {
251       if (link->data == owner)
252         return TRUE;
253       
254       link = _dbus_list_get_next_link (&service->owners, link);
255     }
256
257   return FALSE;
258 }