services.c revision 97ee8d189948c9f2c86464ca33f82e6daeaedc72
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
31struct BusService
32{
33  char *name;
34  DBusList *owners;
35
36  unsigned int prohibit_replacement:1;
37};
38
39static DBusHashTable *service_hash = NULL;
40static DBusMemPool   *service_pool = NULL;
41
42BusService*
43bus_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
107dbus_bool_t
108bus_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
128void
129bus_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
157DBusConnection*
158bus_service_get_primary_owner (BusService *service)
159{
160  return _dbus_list_get_first (&service->owners);
161}
162
163const char*
164bus_service_get_name (BusService *service)
165{
166  return service->name;
167}
168
169void
170bus_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
187char **
188bus_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
226void
227bus_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
235dbus_bool_t
236bus_service_get_prohibit_replacement (BusService *service)
237{
238  return service->prohibit_replacement;
239}
240
241dbus_bool_t
242bus_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}
259