services.c revision 90ed1d84588a84697051e643175452c50d682ece
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_ERROR_IS_CLEAR (error); 132 133 _dbus_assert (owner_if_created != NULL); 134 _dbus_assert (transaction != NULL); 135 136 _dbus_string_get_const_data (service_name, &c_name); 137 138 service = _dbus_hash_table_lookup_string (registry->service_hash, 139 c_name); 140 if (service != NULL) 141 return service; 142 143 service = _dbus_mem_pool_alloc (registry->service_pool); 144 if (service == NULL) 145 { 146 BUS_SET_OOM (error); 147 return NULL; 148 } 149 150 service->registry = registry; 151 152 service->name = _dbus_strdup (c_name); 153 if (service->name == NULL) 154 { 155 _dbus_mem_pool_dealloc (registry->service_pool, service); 156 BUS_SET_OOM (error); 157 return NULL; 158 } 159 160 if (!bus_driver_send_service_created (service->name, transaction, error)) 161 { 162 dbus_free (service->name); 163 _dbus_mem_pool_dealloc (registry->service_pool, service); 164 return NULL; 165 } 166 167 if (!bus_activation_service_created (bus_context_get_activation (registry->context), 168 service->name, error)) 169 { 170 dbus_free (service->name); 171 _dbus_mem_pool_dealloc (registry->service_pool, service); 172 return NULL; 173 } 174 175 if (!bus_service_add_owner (service, owner_if_created, 176 transaction, error)) 177 { 178 dbus_free (service->name); 179 _dbus_mem_pool_dealloc (registry->service_pool, service); 180 return NULL; 181 } 182 183 if (!_dbus_hash_table_insert_string (registry->service_hash, 184 service->name, 185 service)) 186 { 187 bus_connection_remove_owned_service (owner_if_created, 188 service); 189 _dbus_list_clear (&service->owners); 190 dbus_free (service->name); 191 _dbus_mem_pool_dealloc (registry->service_pool, service); 192 BUS_SET_OOM (error); 193 return NULL; 194 } 195 196 return service; 197} 198 199void 200bus_registry_foreach (BusRegistry *registry, 201 BusServiceForeachFunction function, 202 void *data) 203{ 204 DBusHashIter iter; 205 206 _dbus_hash_iter_init (registry->service_hash, &iter); 207 while (_dbus_hash_iter_next (&iter)) 208 { 209 BusService *service = _dbus_hash_iter_get_value (&iter); 210 211 (* function) (service, data); 212 } 213} 214 215dbus_bool_t 216bus_registry_list_services (BusRegistry *registry, 217 char ***listp, 218 int *array_len) 219{ 220 int i, j, len; 221 char **retval; 222 DBusHashIter iter; 223 224 len = _dbus_hash_table_get_n_entries (registry->service_hash); 225 retval = dbus_new (char *, len + 1); 226 227 if (retval == NULL) 228 return FALSE; 229 230 _dbus_hash_iter_init (registry->service_hash, &iter); 231 i = 0; 232 while (_dbus_hash_iter_next (&iter)) 233 { 234 BusService *service = _dbus_hash_iter_get_value (&iter); 235 236 retval[i] = _dbus_strdup (service->name); 237 if (retval[i] == NULL) 238 goto error; 239 240 i++; 241 } 242 243 retval[i] = NULL; 244 245 if (array_len) 246 *array_len = len; 247 248 *listp = retval; 249 return TRUE; 250 251 error: 252 for (j = 0; j < i; j++) 253 dbus_free (retval[i]); 254 dbus_free (retval); 255 256 return FALSE; 257} 258 259dbus_bool_t 260bus_service_add_owner (BusService *service, 261 DBusConnection *owner, 262 BusTransaction *transaction, 263 DBusError *error) 264{ 265 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 266 267 /* Send service acquired message first, OOM will result 268 * in cancelling the transaction 269 */ 270 if (service->owners == NULL) 271 { 272 if (!bus_driver_send_service_acquired (owner, service->name, transaction, error)) 273 return FALSE; 274 } 275 276 if (!_dbus_list_append (&service->owners, 277 owner)) 278 { 279 BUS_SET_OOM (error); 280 return FALSE; 281 } 282 283 if (!bus_connection_add_owned_service (owner, service)) 284 { 285 _dbus_list_remove_last (&service->owners, owner); 286 BUS_SET_OOM (error); 287 return FALSE; 288 } 289 290 return TRUE; 291} 292 293dbus_bool_t 294bus_service_remove_owner (BusService *service, 295 DBusConnection *owner, 296 BusTransaction *transaction, 297 DBusError *error) 298{ 299 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 300 301 /* We send out notifications before we do any work we 302 * might have to undo if the notification-sending failed 303 */ 304 305 /* Send service lost message */ 306 if (bus_service_get_primary_owner (service) == owner) 307 { 308 if (!bus_driver_send_service_lost (owner, service->name, 309 transaction, error)) 310 return FALSE; 311 } 312 313 if (service->owners == NULL) 314 { 315 _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners"); 316 } 317 else if (_dbus_list_length_is_one (&service->owners)) 318 { 319 /* We are the only owner - send service deleted */ 320 if (!bus_driver_send_service_deleted (service->name, 321 transaction, error)) 322 return FALSE; 323 } 324 else 325 { 326 DBusList *link; 327 link = _dbus_list_get_first (&service->owners); 328 _dbus_assert (link != NULL); 329 link = _dbus_list_get_next_link (&service->owners, link); 330 331 if (link != NULL) 332 { 333 /* This will be our new owner */ 334 if (!bus_driver_send_service_acquired (link->data, 335 service->name, 336 transaction, 337 error)) 338 return FALSE; 339 } 340 } 341 342 _dbus_list_remove_last (&service->owners, owner); 343 bus_connection_remove_owned_service (owner, service); 344 345 if (service->owners == NULL) 346 { 347 /* Delete service (already sent message that it was deleted above) */ 348 _dbus_hash_table_remove_string (service->registry->service_hash, 349 service->name); 350 351 dbus_free (service->name); 352 _dbus_mem_pool_dealloc (service->registry->service_pool, service); 353 } 354 355 return TRUE; 356} 357 358DBusConnection* 359bus_service_get_primary_owner (BusService *service) 360{ 361 return _dbus_list_get_first (&service->owners); 362} 363 364const char* 365bus_service_get_name (BusService *service) 366{ 367 return service->name; 368} 369 370void 371bus_service_set_prohibit_replacement (BusService *service, 372 dbus_bool_t prohibit_replacement) 373{ 374 service->prohibit_replacement = prohibit_replacement != FALSE; 375} 376 377dbus_bool_t 378bus_service_get_prohibit_replacement (BusService *service) 379{ 380 return service->prohibit_replacement; 381} 382 383dbus_bool_t 384bus_service_has_owner (BusService *service, 385 DBusConnection *owner) 386{ 387 DBusList *link; 388 389 link = _dbus_list_get_first_link (&service->owners); 390 391 while (link != NULL) 392 { 393 if (link->data == owner) 394 return TRUE; 395 396 link = _dbus_list_get_next_link (&service->owners, link); 397 } 398 399 return FALSE; 400} 401