services.c revision 3f4086f0fdd1cc7fc03585ec9f750897fb3c1d55
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 <dbus/dbus-hash.h> 25#include <dbus/dbus-list.h> 26#include <dbus/dbus-mempool.h> 27 28#include "driver.h" 29#include "services.h" 30#include "connection.h" 31#include "utils.h" 32#include "activation.h" 33 34struct BusService 35{ 36 BusRegistry *registry; 37 char *name; 38 DBusList *owners; 39 40 unsigned int prohibit_replacement : 1; 41}; 42 43struct BusRegistry 44{ 45 int refcount; 46 47 BusContext *context; 48 49 DBusHashTable *service_hash; 50 DBusMemPool *service_pool; 51}; 52 53BusRegistry* 54bus_registry_new (BusContext *context) 55{ 56 BusRegistry *registry; 57 58 registry = dbus_new0 (BusRegistry, 1); 59 if (registry == NULL) 60 return NULL; 61 62 registry->refcount = 1; 63 registry->context = context; 64 65 registry->service_hash = _dbus_hash_table_new (DBUS_HASH_STRING, 66 NULL, NULL); 67 if (registry->service_hash == NULL) 68 goto failed; 69 70 registry->service_pool = _dbus_mem_pool_new (sizeof (BusService), 71 TRUE); 72 if (registry->service_pool == NULL) 73 goto failed; 74 75 return registry; 76 77 failed: 78 bus_registry_unref (registry); 79 return NULL; 80} 81 82void 83bus_registry_ref (BusRegistry *registry) 84{ 85 _dbus_assert (registry->refcount > 0); 86 registry->refcount += 1; 87} 88 89void 90bus_registry_unref (BusRegistry *registry) 91{ 92 _dbus_assert (registry->refcount > 0); 93 registry->refcount -= 1; 94 95 if (registry->refcount == 0) 96 { 97 if (registry->service_hash) 98 _dbus_hash_table_unref (registry->service_hash); 99 if (registry->service_pool) 100 _dbus_mem_pool_free (registry->service_pool); 101 102 dbus_free (registry); 103 } 104} 105 106BusService* 107bus_registry_lookup (BusRegistry *registry, 108 const DBusString *service_name) 109{ 110 const char *c_name; 111 BusService *service; 112 113 _dbus_string_get_const_data (service_name, &c_name); 114 115 service = _dbus_hash_table_lookup_string (registry->service_hash, 116 c_name); 117 118 return service; 119} 120 121BusService* 122bus_registry_ensure (BusRegistry *registry, 123 const DBusString *service_name, 124 DBusConnection *owner_if_created, 125 BusTransaction *transaction, 126 DBusError *error) 127{ 128 const char *c_name; 129 BusService *service; 130 131 _dbus_assert (owner_if_created != NULL); 132 _dbus_assert (transaction != NULL); 133 134 _dbus_string_get_const_data (service_name, &c_name); 135 136 service = _dbus_hash_table_lookup_string (registry->service_hash, 137 c_name); 138 if (service != NULL) 139 return service; 140 141 service = _dbus_mem_pool_alloc (registry->service_pool); 142 if (service == NULL) 143 { 144 BUS_SET_OOM (error); 145 return NULL; 146 } 147 148 service->registry = registry; 149 150 service->name = _dbus_strdup (c_name); 151 if (service->name == NULL) 152 { 153 _dbus_mem_pool_dealloc (registry->service_pool, service); 154 BUS_SET_OOM (error); 155 return NULL; 156 } 157 158 if (!bus_driver_send_service_created (service->name, transaction, error)) 159 { 160 dbus_free (service->name); 161 _dbus_mem_pool_dealloc (registry->service_pool, service); 162 return NULL; 163 } 164 165 if (!bus_activation_service_created (bus_context_get_activation (registry->context), 166 service->name, error)) 167 { 168 dbus_free (service->name); 169 _dbus_mem_pool_dealloc (registry->service_pool, service); 170 return NULL; 171 } 172 173 if (!bus_service_add_owner (service, owner_if_created, 174 transaction, error)) 175 { 176 dbus_free (service->name); 177 _dbus_mem_pool_dealloc (registry->service_pool, service); 178 return NULL; 179 } 180 181 if (!_dbus_hash_table_insert_string (registry->service_hash, 182 service->name, 183 service)) 184 { 185 bus_connection_remove_owned_service (owner_if_created, 186 service); 187 _dbus_list_clear (&service->owners); 188 dbus_free (service->name); 189 _dbus_mem_pool_dealloc (registry->service_pool, service); 190 BUS_SET_OOM (error); 191 return NULL; 192 } 193 194 return service; 195} 196 197void 198bus_registry_foreach (BusRegistry *registry, 199 BusServiceForeachFunction function, 200 void *data) 201{ 202 DBusHashIter iter; 203 204 _dbus_hash_iter_init (registry->service_hash, &iter); 205 while (_dbus_hash_iter_next (&iter)) 206 { 207 BusService *service = _dbus_hash_iter_get_value (&iter); 208 209 (* function) (service, data); 210 } 211} 212 213dbus_bool_t 214bus_registry_list_services (BusRegistry *registry, 215 char ***listp, 216 int *array_len) 217{ 218 int i, j, len; 219 char **retval; 220 DBusHashIter iter; 221 222 len = _dbus_hash_table_get_n_entries (registry->service_hash); 223 retval = dbus_new (char *, len + 1); 224 225 if (retval == NULL) 226 return FALSE; 227 228 _dbus_hash_iter_init (registry->service_hash, &iter); 229 i = 0; 230 while (_dbus_hash_iter_next (&iter)) 231 { 232 BusService *service = _dbus_hash_iter_get_value (&iter); 233 234 retval[i] = _dbus_strdup (service->name); 235 if (retval[i] == NULL) 236 goto error; 237 238 i++; 239 } 240 241 retval[i] = NULL; 242 243 if (array_len) 244 *array_len = len; 245 246 *listp = retval; 247 return TRUE; 248 249 error: 250 for (j = 0; j < i; j++) 251 dbus_free (retval[i]); 252 dbus_free (retval); 253 254 return FALSE; 255} 256 257dbus_bool_t 258bus_service_add_owner (BusService *service, 259 DBusConnection *owner, 260 BusTransaction *transaction, 261 DBusError *error) 262{ 263 /* Send service acquired message first, OOM will result 264 * in cancelling the transaction 265 */ 266 if (service->owners == NULL) 267 { 268 if (!bus_driver_send_service_acquired (owner, service->name, transaction, error)) 269 return FALSE; 270 } 271 272 if (!_dbus_list_append (&service->owners, 273 owner)) 274 { 275 BUS_SET_OOM (error); 276 return FALSE; 277 } 278 279 if (!bus_connection_add_owned_service (owner, service)) 280 { 281 _dbus_list_remove_last (&service->owners, owner); 282 BUS_SET_OOM (error); 283 return FALSE; 284 } 285 286 return TRUE; 287} 288 289dbus_bool_t 290bus_service_remove_owner (BusService *service, 291 DBusConnection *owner, 292 BusTransaction *transaction, 293 DBusError *error) 294{ 295 /* We send out notifications before we do any work we 296 * might have to undo if the notification-sending failed 297 */ 298 299 /* Send service lost message */ 300 if (bus_service_get_primary_owner (service) == owner) 301 { 302 if (!bus_driver_send_service_lost (owner, service->name, 303 transaction, error)) 304 return FALSE; 305 } 306 307 if (service->owners == NULL) 308 { 309 _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners"); 310 } 311 else if (_dbus_list_length_is_one (&service->owners)) 312 { 313 /* We are the only owner - send service deleted */ 314 if (!bus_driver_send_service_deleted (service->name, 315 transaction, error)) 316 return FALSE; 317 } 318 else 319 { 320 DBusList *link; 321 link = _dbus_list_get_first (&service->owners); 322 _dbus_assert (link != NULL); 323 link = _dbus_list_get_next_link (&service->owners, link); 324 325 if (link != NULL) 326 { 327 /* This will be our new owner */ 328 if (!bus_driver_send_service_acquired (link->data, 329 service->name, 330 transaction, 331 error)) 332 return FALSE; 333 } 334 } 335 336 _dbus_list_remove_last (&service->owners, owner); 337 bus_connection_remove_owned_service (owner, service); 338 339 if (service->owners == NULL) 340 { 341 /* Delete service (already sent message that it was deleted above) */ 342 _dbus_hash_table_remove_string (service->registry->service_hash, 343 service->name); 344 345 dbus_free (service->name); 346 _dbus_mem_pool_dealloc (service->registry->service_pool, service); 347 } 348 349 return TRUE; 350} 351 352DBusConnection* 353bus_service_get_primary_owner (BusService *service) 354{ 355 return _dbus_list_get_first (&service->owners); 356} 357 358const char* 359bus_service_get_name (BusService *service) 360{ 361 return service->name; 362} 363 364void 365bus_service_set_prohibit_replacement (BusService *service, 366 dbus_bool_t prohibit_replacement) 367{ 368 service->prohibit_replacement = prohibit_replacement != FALSE; 369} 370 371dbus_bool_t 372bus_service_get_prohibit_replacement (BusService *service) 373{ 374 return service->prohibit_replacement; 375} 376 377dbus_bool_t 378bus_service_has_owner (BusService *service, 379 DBusConnection *owner) 380{ 381 DBusList *link; 382 383 link = _dbus_list_get_first_link (&service->owners); 384 385 while (link != NULL) 386 { 387 if (link->data == owner) 388 return TRUE; 389 390 link = _dbus_list_get_next_link (&service->owners, link); 391 } 392 393 return FALSE; 394} 395