2003-01-27 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   return service;
103 }
104
105 dbus_bool_t
106 bus_service_add_owner (BusService     *service,
107                        DBusConnection *owner)
108 {
109   if (!_dbus_list_append (&service->owners,
110                           owner))
111     return FALSE;
112
113   if (!bus_connection_add_owned_service (owner, service))
114     {
115       _dbus_list_remove_last (&service->owners, owner);
116       return FALSE;
117     }
118
119  /* Send service acquired message */
120   if (bus_service_get_primary_owner (service) == owner)
121     bus_driver_send_service_acquired (owner, service->name);
122   
123   return TRUE;
124 }
125
126 void
127 bus_service_remove_owner (BusService     *service,
128                           DBusConnection *owner)
129 {
130   /* Send service lost message */
131   if (bus_service_get_primary_owner (service) == owner)
132     bus_driver_send_service_lost (owner, service->name);
133   
134   _dbus_list_remove_last (&service->owners, owner);
135   bus_connection_remove_owned_service (owner, service);
136
137   if (service->owners == NULL)
138     {
139       /* Delete service */
140       bus_driver_send_service_deleted (service->name);
141       
142       _dbus_hash_table_remove_string (service_hash, service->name);
143       
144       dbus_free (service->name);
145       _dbus_mem_pool_dealloc (service_pool, service);
146     }
147   else 
148     {
149       /* Send service acquired to the new owner */
150       bus_driver_send_service_acquired (bus_service_get_primary_owner (service),
151                                         service->name);
152     }
153 }
154
155 DBusConnection*
156 bus_service_get_primary_owner (BusService *service)
157 {
158   return _dbus_list_get_first (&service->owners);
159 }
160
161 const char*
162 bus_service_get_name (BusService *service)
163 {
164   return service->name;
165 }
166
167 void
168 bus_service_foreach (BusServiceForeachFunction  function,
169                      void                      *data)
170 {
171   DBusHashIter iter;
172   
173   if (service_hash == NULL)
174     return;
175   
176   _dbus_hash_iter_init (service_hash, &iter);
177   while (_dbus_hash_iter_next (&iter))
178     {
179       BusService *service = _dbus_hash_iter_get_value (&iter);
180
181       (* function) (service, data);
182     }
183 }
184
185 char **
186 bus_services_list (int *array_len)
187 {
188   int i, j, len;
189   char **retval;
190   DBusHashIter iter;
191    
192   len = _dbus_hash_table_get_n_entries (service_hash);
193   retval = dbus_new (char *, len);
194
195   if (retval == NULL)
196     return NULL;
197
198   _dbus_hash_iter_init (service_hash, &iter);
199   i = 0;
200   while (_dbus_hash_iter_next (&iter))
201     {
202       BusService *service = _dbus_hash_iter_get_value (&iter);
203
204       retval[i] = _dbus_strdup (service->name);
205       if (retval[i] == NULL)
206         goto error;
207
208       i++;
209     }
210
211   if (array_len)
212     *array_len = len;
213   
214   return retval;
215   
216  error:
217   for (j = 0; j < i; j++)
218     dbus_free (retval[i]);
219   dbus_free (retval);
220
221   return NULL;
222 }
223
224 void
225 bus_service_set_prohibit_replacement (BusService  *service,
226                                       dbus_bool_t  prohibit_replacement)
227 {
228   _dbus_assert (service->owners == NULL);
229   
230   service->prohibit_replacement = prohibit_replacement != FALSE;
231 }
232
233 dbus_bool_t
234 bus_service_get_prohibit_replacement (BusService *service)
235 {
236   return service->prohibit_replacement;
237 }
238
239 dbus_bool_t
240 bus_service_has_owner (BusService     *service,
241                        DBusConnection *owner)
242 {
243   DBusList *link;
244
245   link = _dbus_list_get_first_link (&service->owners);
246   
247   while (link != NULL)
248     {
249       if (link->data == owner)
250         return TRUE;
251       
252       link = _dbus_list_get_next_link (&service->owners, link);
253     }
254
255   return FALSE;
256 }