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