Patches by Kjartan Maraas <kmaraas at gnome dot org>
[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 2.1
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 #include <dbus/dbus-marshal-validate.h>
28
29 #include "driver.h"
30 #include "services.h"
31 #include "connection.h"
32 #include "utils.h"
33 #include "activation.h"
34 #include "policy.h"
35 #include "bus.h"
36 #include "selinux.h"
37
38 struct BusService
39 {
40   int refcount;
41
42   BusRegistry *registry;
43   char *name;
44   DBusList *owners;
45 };
46
47 struct BusOwner
48 {
49   int refcount;
50
51   BusService *service;
52   DBusConnection *conn;
53
54   unsigned int allow_replacement : 1;
55   unsigned int do_not_queue : 1;
56 };
57
58 struct BusRegistry
59 {
60   int refcount;
61
62   BusContext *context;
63   
64   DBusHashTable *service_hash;
65   DBusMemPool   *service_pool;
66   DBusMemPool   *owner_pool;
67
68   DBusHashTable *service_sid_table;
69 };
70
71 BusRegistry*
72 bus_registry_new (BusContext *context)
73 {
74   BusRegistry *registry;
75
76   registry = dbus_new0 (BusRegistry, 1);
77   if (registry == NULL)
78     return NULL;
79
80   registry->refcount = 1;
81   registry->context = context;
82   
83   registry->service_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
84                                                  NULL, NULL);
85   if (registry->service_hash == NULL)
86     goto failed;
87   
88   registry->service_pool = _dbus_mem_pool_new (sizeof (BusService),
89                                                TRUE);
90
91   if (registry->service_pool == NULL)
92     goto failed;
93
94   registry->owner_pool = _dbus_mem_pool_new (sizeof (BusOwner),
95                                              TRUE);
96
97   if (registry->owner_pool == NULL)
98     goto failed;
99
100   registry->service_sid_table = NULL;
101   
102   return registry;
103
104  failed:
105   bus_registry_unref (registry);
106   return NULL;
107 }
108
109 BusRegistry *
110 bus_registry_ref (BusRegistry *registry)
111 {
112   _dbus_assert (registry->refcount > 0);
113   registry->refcount += 1;
114
115   return registry;
116 }
117
118 void
119 bus_registry_unref  (BusRegistry *registry)
120 {
121   _dbus_assert (registry->refcount > 0);
122   registry->refcount -= 1;
123
124   if (registry->refcount == 0)
125     {
126       if (registry->service_hash)
127         _dbus_hash_table_unref (registry->service_hash);
128       if (registry->service_pool)
129         _dbus_mem_pool_free (registry->service_pool);
130       if (registry->owner_pool)
131         _dbus_mem_pool_free (registry->owner_pool);
132       if (registry->service_sid_table)
133         _dbus_hash_table_unref (registry->service_sid_table);
134       
135       dbus_free (registry);
136     }
137 }
138
139 BusService*
140 bus_registry_lookup (BusRegistry      *registry,
141                      const DBusString *service_name)
142 {
143   BusService *service;
144
145   service = _dbus_hash_table_lookup_string (registry->service_hash,
146                                             _dbus_string_get_const_data (service_name));
147
148   return service;
149 }
150
151 static DBusList *
152 _bus_service_find_owner_link (BusService *service,
153                               DBusConnection *connection)
154 {
155   DBusList *link;
156   
157   link = _dbus_list_get_first_link (&service->owners);
158
159   while (link != NULL)
160     {
161       BusOwner *bus_owner;
162
163       bus_owner = (BusOwner *) link->data;
164       if (bus_owner->conn == connection) 
165         break;
166
167       link = _dbus_list_get_next_link (&service->owners, link);
168     }
169
170   return link;
171 }
172
173 static void
174 bus_owner_set_flags (BusOwner *owner,
175                      dbus_uint32_t flags)
176 {
177    owner->allow_replacement = 
178         (flags & DBUS_NAME_FLAG_ALLOW_REPLACEMENT) != FALSE;
179
180    owner->do_not_queue =
181         (flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) != FALSE;
182 }
183
184 static BusOwner *
185 bus_owner_new (BusService *service, 
186                DBusConnection *conn, 
187                dbus_uint32_t flags)
188 {
189   BusOwner *result;
190
191   result = _dbus_mem_pool_alloc (service->registry->owner_pool);
192   if (result != NULL)
193     {
194       result->refcount = 1;
195       /* don't ref the connection because we don't want
196          to block the connection from going away.
197          transactions take care of reffing the connection
198          but we need to use refcounting on the owner
199          so that the owner does not get freed before
200          we can deref the connection in the transaction
201        */
202       result->conn = conn;
203       result->service = service;
204
205       if (!bus_connection_add_owned_service (conn, service))
206         {
207           _dbus_mem_pool_dealloc (service->registry->owner_pool, result);
208           return NULL;
209         }
210         
211       bus_owner_set_flags (result, flags);
212     }
213   return result;
214 }
215
216 static BusOwner *
217 bus_owner_ref (BusOwner *owner)
218 {
219   _dbus_assert (owner->refcount > 0);
220   owner->refcount += 1;
221
222   return owner;
223 }
224
225 static void
226 bus_owner_unref  (BusOwner *owner)
227 {
228   _dbus_assert (owner->refcount > 0);
229   owner->refcount -= 1;
230
231   if (owner->refcount == 0)
232     {
233       bus_connection_remove_owned_service (owner->conn, owner->service);
234       _dbus_mem_pool_dealloc (owner->service->registry->owner_pool, owner);
235     }
236 }
237
238 BusService*
239 bus_registry_ensure (BusRegistry               *registry,
240                      const DBusString          *service_name,
241                      DBusConnection            *owner_connection_if_created,
242                      dbus_uint32_t              flags,
243                      BusTransaction            *transaction,
244                      DBusError                 *error)
245 {
246   BusService *service;
247
248   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
249   
250   _dbus_assert (owner_connection_if_created != NULL);
251   _dbus_assert (transaction != NULL);
252
253   service = _dbus_hash_table_lookup_string (registry->service_hash,
254                                             _dbus_string_get_const_data (service_name));
255   if (service != NULL)
256     return service;
257   
258   service = _dbus_mem_pool_alloc (registry->service_pool);
259   if (service == NULL)
260     {
261       BUS_SET_OOM (error);
262       return NULL;
263     }
264
265   service->registry = registry;  
266   service->refcount = 1;
267
268   _dbus_verbose ("copying string %p '%s' to service->name\n",
269                  service_name, _dbus_string_get_const_data (service_name));
270   if (!_dbus_string_copy_data (service_name, &service->name))
271     {
272       _dbus_mem_pool_dealloc (registry->service_pool, service);
273       BUS_SET_OOM (error);
274       return NULL;
275     }
276   _dbus_verbose ("copied string %p '%s' to '%s'\n",
277                  service_name, _dbus_string_get_const_data (service_name),
278                  service->name);
279
280   if (!bus_driver_send_service_owner_changed (service->name, 
281                                               NULL,
282                                               bus_connection_get_name (owner_connection_if_created),
283                                               transaction, error))
284     {
285       bus_service_unref (service);
286       return NULL;
287     }
288
289   if (!bus_activation_service_created (bus_context_get_activation (registry->context),
290                                        service->name, transaction, error))
291     {
292       bus_service_unref (service);
293       return NULL;
294     }
295   
296   if (!bus_service_add_owner (service, owner_connection_if_created, flags,
297                                               transaction, error))
298     {
299       bus_service_unref (service);
300       return NULL;
301     }
302   
303   if (!_dbus_hash_table_insert_string (registry->service_hash,
304                                        service->name,
305                                        service))
306     {
307       /* The add_owner gets reverted on transaction cancel */
308       BUS_SET_OOM (error);
309       return NULL;
310     }
311   
312   return service;
313 }
314
315 void
316 bus_registry_foreach (BusRegistry               *registry,
317                       BusServiceForeachFunction  function,
318                       void                      *data)
319 {
320   DBusHashIter iter;
321   
322   _dbus_hash_iter_init (registry->service_hash, &iter);
323   while (_dbus_hash_iter_next (&iter))
324     {
325       BusService *service = _dbus_hash_iter_get_value (&iter);
326
327       (* function) (service, data);
328     }
329 }
330
331 dbus_bool_t
332 bus_registry_list_services (BusRegistry *registry,
333                             char      ***listp,
334                             int         *array_len)
335 {
336   int i, j, len;
337   char **retval;
338   DBusHashIter iter;
339    
340   len = _dbus_hash_table_get_n_entries (registry->service_hash);
341   retval = dbus_new (char *, len + 1);
342
343   if (retval == NULL)
344     return FALSE;
345
346   _dbus_hash_iter_init (registry->service_hash, &iter);
347   i = 0;
348   while (_dbus_hash_iter_next (&iter))
349     {
350       BusService *service = _dbus_hash_iter_get_value (&iter);
351
352       retval[i] = _dbus_strdup (service->name);
353       if (retval[i] == NULL)
354         goto error;
355
356       i++;
357     }
358
359   retval[i] = NULL;
360   
361   if (array_len)
362     *array_len = len;
363   
364   *listp = retval;
365   return TRUE;
366   
367  error:
368   for (j = 0; j < i; j++)
369     dbus_free (retval[i]);
370   dbus_free (retval);
371
372   return FALSE;
373 }
374
375 dbus_bool_t
376 bus_registry_acquire_service (BusRegistry      *registry,
377                               DBusConnection   *connection,
378                               const DBusString *service_name,
379                               dbus_uint32_t     flags,
380                               dbus_uint32_t    *result,
381                               BusTransaction   *transaction,
382                               DBusError        *error)
383 {
384   dbus_bool_t retval;
385   DBusConnection *old_owner_conn;
386   DBusConnection *current_owner_conn;
387   BusClientPolicy *policy;
388   BusService *service;
389   BusActivation  *activation;
390   BusSELinuxID *sid;
391   BusOwner *primary_owner;
392  
393   retval = FALSE;
394
395   if (!_dbus_validate_bus_name (service_name, 0,
396                                 _dbus_string_get_length (service_name)))
397     {
398       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
399                       "Requested bus name \"%s\" is not valid",
400                       _dbus_string_get_const_data (service_name));
401       
402       _dbus_verbose ("Attempt to acquire invalid service name\n");
403       
404       goto out;
405     }
406   
407   if (_dbus_string_get_byte (service_name, 0) == ':')
408     {
409       /* Not allowed; only base services can start with ':' */
410       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
411                       "Cannot acquire a service starting with ':' such as \"%s\"",
412                       _dbus_string_get_const_data (service_name));
413       
414       _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"",
415                      _dbus_string_get_const_data (service_name));
416       
417       goto out;
418     }
419
420   policy = bus_connection_get_policy (connection);
421   _dbus_assert (policy != NULL);
422
423   /* Note that if sid is #NULL then the bus's own context gets used
424    * in bus_connection_selinux_allows_acquire_service()
425    */
426   sid = bus_selinux_id_table_lookup (registry->service_sid_table,
427                                      service_name);
428
429   if (!bus_selinux_allows_acquire_service (connection, sid,
430                                            _dbus_string_get_const_data (service_name), error))
431     {
432
433       if (dbus_error_is_set (error) &&
434           dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY))
435         {
436           goto out;
437         }
438
439       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
440                       "Connection \"%s\" is not allowed to own the service \"%s\" due "
441                       "to SELinux policy",
442                       bus_connection_is_active (connection) ?
443                       bus_connection_get_name (connection) :
444                       "(inactive)",
445                       _dbus_string_get_const_data (service_name));
446       goto out;
447     }
448       
449   if (!bus_client_policy_check_can_own (policy, connection,
450                                         service_name))
451     {
452       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
453                       "Connection \"%s\" is not allowed to own the service \"%s\" due "
454                       "to security policies in the configuration file",
455                       bus_connection_is_active (connection) ?
456                       bus_connection_get_name (connection) :
457                       "(inactive)",
458                       _dbus_string_get_const_data (service_name));
459       goto out;
460     }
461
462   if (bus_connection_get_n_services_owned (connection) >=
463       bus_context_get_max_services_per_connection (registry->context))
464     {
465       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
466                       "Connection \"%s\" is not allowed to own more services "
467                       "(increase limits in configuration file if required)",
468                       bus_connection_is_active (connection) ?
469                       bus_connection_get_name (connection) :
470                       "(inactive)");
471       goto out;
472     }
473   
474   service = bus_registry_lookup (registry, service_name);
475
476   if (service != NULL)
477     {
478       primary_owner = bus_service_get_primary_owner (service);
479       if (primary_owner != NULL)
480         old_owner_conn = primary_owner->conn;
481       else
482         old_owner_conn = NULL;
483     }
484   else
485     old_owner_conn = NULL;
486       
487   if (service == NULL)
488     {
489       service = bus_registry_ensure (registry,
490                                      service_name, connection, flags,
491                                      transaction, error);
492       if (service == NULL)
493         goto out;
494     }
495
496   primary_owner = bus_service_get_primary_owner (service);
497   if (primary_owner == NULL)
498     goto out;
499     
500   current_owner_conn = primary_owner->conn;
501      
502   if (old_owner_conn == NULL)
503     {
504       _dbus_assert (current_owner_conn == connection);
505
506       *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;      
507     }
508   else if (old_owner_conn == connection)
509     {
510       bus_owner_set_flags (primary_owner, flags);
511       *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
512     }
513   else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
514            !(bus_service_get_allow_replacement (service))) ||
515            ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
516            !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) 
517     {
518       DBusList *link;
519       BusOwner *temp_owner;
520     /* Since we can't be queued if we are already in the queue
521        remove us */
522
523       link = _bus_service_find_owner_link (service, connection);
524       if (link != NULL)
525         {
526           _dbus_list_unlink (&service->owners, link);
527           temp_owner = (BusOwner *)link->data;
528           bus_owner_unref (temp_owner); 
529           _dbus_list_free_link (link);
530         }
531       
532       *result = DBUS_REQUEST_NAME_REPLY_EXISTS;
533     }
534   else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
535            (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) ||
536             !(bus_service_get_allow_replacement (service))))
537     {
538       /* Queue the connection */
539       if (!bus_service_add_owner (service, connection, 
540                                   flags,
541                                   transaction, error))
542         goto out;
543       
544       *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE;
545     }
546   else
547     {
548       /* Replace the current owner */
549
550       /* We enqueue the new owner and remove the first one because
551        * that will cause NameAcquired and NameLost messages to
552        * be sent.
553        */
554       
555       if (!bus_service_add_owner (service, connection,
556                                   flags,
557                                   transaction, error))
558         goto out;
559
560       if (primary_owner->do_not_queue)
561         {
562           if (!bus_service_remove_owner (service, old_owner_conn,
563                                          transaction, error))
564             goto out;
565         }
566       else
567         {
568           if (!bus_service_swap_owner (service, old_owner_conn,
569                                        transaction, error))
570             goto out;
571         }
572         
573     
574       _dbus_assert (connection == bus_service_get_primary_owner (service)->conn);
575       *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
576     }
577
578   activation = bus_context_get_activation (registry->context);
579   retval = bus_activation_send_pending_auto_activation_messages (activation,
580                                                                  service,
581                                                                  transaction,
582                                                                  error);
583   
584  out:
585   return retval;
586 }
587
588 dbus_bool_t
589 bus_registry_release_service (BusRegistry      *registry,
590                               DBusConnection   *connection,
591                               const DBusString *service_name,
592                               dbus_uint32_t    *result,
593                               BusTransaction   *transaction,
594                               DBusError        *error)
595 {
596   dbus_bool_t retval;
597   BusService *service;
598
599   retval = FALSE;
600
601   if (!_dbus_validate_bus_name (service_name, 0,
602                                 _dbus_string_get_length (service_name)))
603     {
604       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
605                       "Given bus name \"%s\" is not valid",
606                       _dbus_string_get_const_data (service_name));
607
608       _dbus_verbose ("Attempt to release invalid service name\n");
609
610       goto out;
611     }
612
613   if (_dbus_string_get_byte (service_name, 0) == ':')
614     {
615       /* Not allowed; the base service name cannot be created or released */
616       dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
617                       "Cannot release a service starting with ':' such as \"%s\"",
618                       _dbus_string_get_const_data (service_name));
619
620       _dbus_verbose ("Attempt to release invalid base service name \"%s\"",
621                      _dbus_string_get_const_data (service_name));
622
623       goto out;
624     }
625
626   service = bus_registry_lookup (registry, service_name);
627
628   if (service == NULL)
629     {
630       *result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT;
631     }
632   else if (!bus_service_has_owner (service, connection))
633     {
634       *result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER;
635     }
636   else
637     {
638       if (!bus_service_remove_owner (service, connection,
639                                      transaction, error))
640         goto out;
641
642       _dbus_assert (!bus_service_has_owner (service, connection));
643       *result = DBUS_RELEASE_NAME_REPLY_RELEASED;
644     }
645
646   retval = TRUE;
647
648  out:
649   return retval;
650 }
651
652 dbus_bool_t
653 bus_registry_set_service_context_table (BusRegistry   *registry,
654                                         DBusHashTable *table)
655 {
656   DBusHashTable *new_table;
657   DBusHashIter iter;
658   
659   new_table = bus_selinux_id_table_new ();
660   if (!new_table)
661     return FALSE;
662
663   _dbus_hash_iter_init (table, &iter);
664   while (_dbus_hash_iter_next (&iter))
665     {
666       const char *service = _dbus_hash_iter_get_string_key (&iter);
667       const char *context = _dbus_hash_iter_get_value (&iter);
668
669       if (!bus_selinux_id_table_insert (new_table,
670                                         service,
671                                         context))
672         return FALSE;
673     }
674   
675   if (registry->service_sid_table)
676     _dbus_hash_table_unref (registry->service_sid_table);
677   registry->service_sid_table = new_table;
678   return TRUE;
679 }
680
681 static void
682 bus_service_unlink_owner (BusService      *service,
683                           BusOwner        *owner)
684 {
685   _dbus_list_remove_last (&service->owners, owner);
686   bus_owner_unref (owner);
687 }
688
689 static void
690 bus_service_unlink (BusService *service)
691 {
692   _dbus_assert (service->owners == NULL);
693
694   /* the service may not be in the hash, if
695    * the failure causing transaction cancel
696    * was in the right place, but that's OK
697    */
698   _dbus_hash_table_remove_string (service->registry->service_hash,
699                                   service->name);
700   
701   bus_service_unref (service);
702 }
703
704 static void
705 bus_service_relink (BusService           *service,
706                     DBusPreallocatedHash *preallocated)
707 {
708   _dbus_assert (service->owners == NULL);
709   _dbus_assert (preallocated != NULL);
710
711   _dbus_hash_table_insert_string_preallocated (service->registry->service_hash,
712                                                preallocated,
713                                                service->name,
714                                                service);
715   
716   bus_service_ref (service);
717 }
718
719 /**
720  * Data used to represent an ownership cancellation in
721  * a bus transaction.
722  */
723 typedef struct
724 {
725   BusOwner *owner;            /**< the owner */
726   BusService *service;        /**< service to cancel ownership of */
727 } OwnershipCancelData;
728
729 static void
730 cancel_ownership (void *data)
731 {
732   OwnershipCancelData *d = data;
733
734   /* We don't need to send messages notifying of these
735    * changes, since we're reverting something that was
736    * cancelled (effectively never really happened)
737    */
738   bus_service_unlink_owner (d->service, d->owner);
739   
740   if (d->service->owners == NULL)
741     bus_service_unlink (d->service);
742 }
743
744 static void
745 free_ownership_cancel_data (void *data)
746 {
747   OwnershipCancelData *d = data;
748
749   dbus_connection_unref (d->owner->conn);
750   bus_owner_unref (d->owner);
751   bus_service_unref (d->service);
752   
753   dbus_free (d);
754 }
755
756 static dbus_bool_t
757 add_cancel_ownership_to_transaction (BusTransaction *transaction,
758                                      BusService     *service,
759                                      BusOwner       *owner)
760 {
761   OwnershipCancelData *d;
762
763   d = dbus_new (OwnershipCancelData, 1);
764   if (d == NULL)
765     return FALSE;
766   
767   d->service = service;
768   d->owner = owner;
769
770   if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d,
771                                         free_ownership_cancel_data))
772     {
773       dbus_free (d);
774       return FALSE;
775     }
776
777   bus_service_ref (d->service);
778   bus_owner_ref (owner);
779   dbus_connection_ref (d->owner->conn);
780  
781   return TRUE;
782 }
783
784 /* this function is self-cancelling if you cancel the transaction */
785 dbus_bool_t
786 bus_service_add_owner (BusService     *service,
787                        DBusConnection *connection,
788                        dbus_uint32_t  flags,
789                        BusTransaction *transaction,
790                        DBusError      *error)
791 {
792   BusOwner *bus_owner;
793   DBusList *bus_owner_link;
794   
795   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
796   
797  /* Send service acquired message first, OOM will result
798   * in cancelling the transaction
799   */
800   if (service->owners == NULL)
801     {
802       if (!bus_driver_send_service_acquired (connection, service->name, transaction, error))
803         return FALSE;
804     }
805   
806   bus_owner_link = _bus_service_find_owner_link (service, connection);
807   
808   if (bus_owner_link == NULL)
809     {
810       bus_owner = bus_owner_new (service, connection, flags);
811       if (bus_owner == NULL)
812         {
813           BUS_SET_OOM (error);
814           return FALSE;
815         }
816
817       bus_owner_set_flags (bus_owner, flags);
818       if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL)
819         {
820           if (!_dbus_list_append (&service->owners,
821                                   bus_owner))
822             {
823               bus_owner_unref (bus_owner);
824               BUS_SET_OOM (error);
825               return FALSE;
826             }
827         }
828       else
829         {
830           if (!_dbus_list_insert_after (&service->owners,
831                                          _dbus_list_get_first_link (&service->owners),
832                                          bus_owner))
833             {
834               bus_owner_unref (bus_owner);
835               BUS_SET_OOM (error);
836               return FALSE;
837             }
838         }      
839     } 
840   else 
841     {
842       /* Update the link since we are already in the queue
843        * No need for operations that can produce OOM
844        */
845
846       bus_owner = (BusOwner *) bus_owner_link->data;
847       if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING)
848         {
849           DBusList *link;
850           _dbus_list_unlink (&service->owners, bus_owner_link);
851           link = _dbus_list_get_first_link (&service->owners);
852           _dbus_assert (link != NULL);
853           
854           _dbus_list_insert_after_link (&service->owners, link, bus_owner_link);
855         }
856       
857       bus_owner_set_flags (bus_owner, flags);
858       return TRUE;
859     }
860
861   if (!add_cancel_ownership_to_transaction (transaction,
862                                             service,
863                                             bus_owner))
864     {
865       bus_service_unlink_owner (service, bus_owner);
866       BUS_SET_OOM (error);
867       return FALSE;
868     }
869
870   return TRUE;
871 }
872
873 typedef struct
874 {
875   BusOwner       *owner;
876   BusService     *service;
877   BusOwner       *before_owner; /* restore to position before this connection in owners list */
878   DBusList       *owner_link;
879   DBusList       *service_link;
880   DBusPreallocatedHash *hash_entry;
881 } OwnershipRestoreData;
882
883 static void
884 restore_ownership (void *data)
885 {
886   OwnershipRestoreData *d = data;
887   DBusList *link;
888
889   _dbus_assert (d->service_link != NULL);
890   _dbus_assert (d->owner_link != NULL);
891   
892   if (d->service->owners == NULL)
893     {
894       _dbus_assert (d->hash_entry != NULL);
895       bus_service_relink (d->service, d->hash_entry);
896     }
897   else
898     {
899       _dbus_assert (d->hash_entry == NULL);
900     }
901   
902   /* We don't need to send messages notifying of these
903    * changes, since we're reverting something that was
904    * cancelled (effectively never really happened)
905    */
906   link = _dbus_list_get_first_link (&d->service->owners);
907   while (link != NULL)
908     {
909       if (link->data == d->before_owner)
910         break;
911
912       link = _dbus_list_get_next_link (&d->service->owners, link);
913     }
914   
915   _dbus_list_insert_before_link (&d->service->owners, link, d->owner_link);
916
917   /* Note that removing then restoring this changes the order in which
918    * ServiceDeleted messages are sent on destruction of the
919    * connection.  This should be OK as the only guarantee there is
920    * that the base service is destroyed last, and we never even
921    * tentatively remove the base service.
922    */
923   bus_connection_add_owned_service_link (d->owner->conn, d->service_link);
924   
925   d->hash_entry = NULL;
926   d->service_link = NULL;
927   d->owner_link = NULL;
928 }
929
930 static void
931 free_ownership_restore_data (void *data)
932 {
933   OwnershipRestoreData *d = data;
934
935   if (d->service_link)
936     _dbus_list_free_link (d->service_link);
937   if (d->owner_link)
938     _dbus_list_free_link (d->owner_link);
939   if (d->hash_entry)
940     _dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash,
941                                               d->hash_entry);
942
943   dbus_connection_unref (d->owner->conn);
944   bus_owner_unref (d->owner);
945   bus_service_unref (d->service);
946   
947   dbus_free (d);
948 }
949
950 static dbus_bool_t
951 add_restore_ownership_to_transaction (BusTransaction *transaction,
952                                       BusService     *service,
953                                       BusOwner       *owner)
954 {
955   OwnershipRestoreData *d;
956   DBusList *link;
957
958   d = dbus_new (OwnershipRestoreData, 1);
959   if (d == NULL)
960     return FALSE;
961   
962   d->service = service;
963   d->owner = owner;
964   d->service_link = _dbus_list_alloc_link (service);
965   d->owner_link = _dbus_list_alloc_link (owner);
966   d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash);
967   
968   bus_service_ref (d->service);
969   bus_owner_ref (d->owner);
970   dbus_connection_ref (d->owner->conn);
971
972   d->before_owner = NULL;
973   link = _dbus_list_get_first_link (&service->owners);
974   while (link != NULL)
975     {
976       if (link->data == owner)
977         {
978           link = _dbus_list_get_next_link (&service->owners, link);
979
980           if (link)
981             d->before_owner = link->data;
982
983           break;
984         }
985       
986       link = _dbus_list_get_next_link (&service->owners, link);
987     }
988   
989   if (d->service_link == NULL ||
990       d->owner_link == NULL ||
991       d->hash_entry == NULL ||
992       !bus_transaction_add_cancel_hook (transaction, restore_ownership, d,
993                                         free_ownership_restore_data))
994     {
995       free_ownership_restore_data (d);
996       return FALSE;
997     }
998   
999   return TRUE;
1000 }
1001
1002 dbus_bool_t
1003 bus_service_swap_owner (BusService     *service,
1004                         DBusConnection *connection,
1005                         BusTransaction *transaction,
1006                         DBusError      *error)
1007 {
1008   DBusList *swap_link;
1009   BusOwner *primary_owner;
1010
1011   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1012
1013   /* We send out notifications before we do any work we
1014    * might have to undo if the notification-sending failed
1015    */
1016   
1017   /* Send service lost message */
1018   primary_owner = bus_service_get_primary_owner (service);
1019   if (primary_owner == NULL || primary_owner->conn != connection)
1020     _dbus_assert_not_reached ("Tried to swap a non primary owner");
1021
1022     
1023   if (!bus_driver_send_service_lost (connection, service->name,
1024                                      transaction, error))
1025     return FALSE;
1026
1027   if (service->owners == NULL)
1028     {
1029       _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners");
1030     }
1031   else if (_dbus_list_length_is_one (&service->owners))
1032     {
1033       _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue");
1034     }
1035   else
1036     {
1037       DBusList *link;
1038       BusOwner *new_owner;
1039       DBusConnection *new_owner_conn;
1040       link = _dbus_list_get_first_link (&service->owners);
1041       _dbus_assert (link != NULL);
1042       link = _dbus_list_get_next_link (&service->owners, link);
1043       _dbus_assert (link != NULL);
1044
1045       new_owner = (BusOwner *)link->data;
1046       new_owner_conn = new_owner->conn;
1047
1048       if (!bus_driver_send_service_owner_changed (service->name,
1049                                                   bus_connection_get_name (connection),
1050                                                   bus_connection_get_name (new_owner_conn),
1051                                                   transaction, error))
1052         return FALSE;
1053
1054       /* This will be our new owner */
1055       if (!bus_driver_send_service_acquired (new_owner_conn,
1056                                              service->name,
1057                                              transaction,
1058                                              error))
1059         return FALSE;
1060     }
1061
1062   if (!add_restore_ownership_to_transaction (transaction, service, primary_owner))
1063     {
1064       BUS_SET_OOM (error);
1065       return FALSE;
1066     }
1067
1068   /* unlink the primary and make it the second link */
1069   swap_link = _dbus_list_get_first_link (&service->owners);
1070   _dbus_list_unlink (&service->owners, swap_link);
1071
1072   _dbus_list_insert_after_link (&service->owners,
1073                                 _dbus_list_get_first_link (&service->owners),
1074                                 swap_link);
1075
1076   return TRUE;
1077 }
1078
1079 /* this function is self-cancelling if you cancel the transaction */
1080 dbus_bool_t
1081 bus_service_remove_owner (BusService     *service,
1082                           DBusConnection *connection,
1083                           BusTransaction *transaction,
1084                           DBusError      *error)
1085 {
1086   BusOwner *primary_owner;
1087   
1088   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1089   
1090   /* We send out notifications before we do any work we
1091    * might have to undo if the notification-sending failed
1092    */
1093   
1094   /* Send service lost message */
1095   primary_owner = bus_service_get_primary_owner (service);
1096   if (primary_owner != NULL && primary_owner->conn == connection)
1097     {
1098       if (!bus_driver_send_service_lost (connection, service->name,
1099                                          transaction, error))
1100         return FALSE;
1101     }
1102   else
1103     {
1104       /* if we are not the primary owner then just remove us from the queue */
1105       DBusList *link;
1106       BusOwner *temp_owner;
1107
1108       link = _bus_service_find_owner_link (service, connection);
1109       _dbus_list_unlink (&service->owners, link);
1110       temp_owner = (BusOwner *)link->data;
1111       bus_owner_unref (temp_owner); 
1112       _dbus_list_free_link (link);
1113
1114       return TRUE; 
1115     }
1116
1117   if (service->owners == NULL)
1118     {
1119       _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners");
1120     }
1121   else if (_dbus_list_length_is_one (&service->owners))
1122     {
1123       if (!bus_driver_send_service_owner_changed (service->name,
1124                                                   bus_connection_get_name (connection),
1125                                                   NULL,
1126                                                   transaction, error))
1127         return FALSE;
1128     }
1129   else
1130     {
1131       DBusList *link;
1132       BusOwner *new_owner;
1133       DBusConnection *new_owner_conn;
1134       link = _dbus_list_get_first_link (&service->owners);
1135       _dbus_assert (link != NULL);
1136       link = _dbus_list_get_next_link (&service->owners, link);
1137       _dbus_assert (link != NULL);
1138
1139       new_owner = (BusOwner *)link->data;
1140       new_owner_conn = new_owner->conn;
1141
1142       if (!bus_driver_send_service_owner_changed (service->name,
1143                                                   bus_connection_get_name (connection),
1144                                                   bus_connection_get_name (new_owner_conn),
1145                                                   transaction, error))
1146         return FALSE;
1147
1148       /* This will be our new owner */
1149       if (!bus_driver_send_service_acquired (new_owner_conn,
1150                                              service->name,
1151                                              transaction,
1152                                              error))
1153         return FALSE;
1154     }
1155
1156   if (!add_restore_ownership_to_transaction (transaction, service, primary_owner))
1157     {
1158       BUS_SET_OOM (error);
1159       return FALSE;
1160     }
1161  
1162   bus_service_unlink_owner (service, primary_owner);
1163
1164   if (service->owners == NULL)
1165     bus_service_unlink (service);
1166
1167   return TRUE;
1168 }
1169
1170 BusService *
1171 bus_service_ref (BusService *service)
1172 {
1173   _dbus_assert (service->refcount > 0);
1174   
1175   service->refcount += 1;
1176
1177   return service;
1178 }
1179
1180 void
1181 bus_service_unref (BusService *service)
1182 {
1183   _dbus_assert (service->refcount > 0);
1184   
1185   service->refcount -= 1;
1186
1187   if (service->refcount == 0)
1188     {
1189       _dbus_assert (service->owners == NULL);
1190       
1191       dbus_free (service->name);
1192       _dbus_mem_pool_dealloc (service->registry->service_pool, service);
1193     }
1194 }
1195
1196 DBusConnection *
1197 bus_service_get_primary_owners_connection (BusService *service)
1198 {
1199   BusOwner *owner;
1200
1201   owner = bus_service_get_primary_owner (service);
1202
1203   if (owner != NULL)
1204     return owner->conn;
1205   else
1206     return NULL;
1207 }
1208
1209 BusOwner*
1210 bus_service_get_primary_owner (BusService *service)
1211 {
1212   return _dbus_list_get_first (&service->owners);
1213 }
1214
1215 const char*
1216 bus_service_get_name (BusService *service)
1217 {
1218   return service->name;
1219 }
1220
1221 dbus_bool_t
1222 bus_service_get_allow_replacement (BusService *service)
1223 {
1224   BusOwner *owner;
1225   DBusList *link;
1226  
1227   _dbus_assert (service->owners != NULL);
1228
1229   link = _dbus_list_get_first_link (&service->owners);
1230   owner = (BusOwner *) link->data;
1231
1232   return owner->allow_replacement;
1233 }
1234
1235 dbus_bool_t
1236 bus_service_has_owner (BusService     *service,
1237                        DBusConnection *connection)
1238 {
1239   DBusList *link;
1240
1241   link = _bus_service_find_owner_link (service, connection);
1242  
1243   if (link == NULL)
1244     return FALSE;
1245   else
1246     return TRUE;
1247 }
1248
1249 dbus_bool_t 
1250 bus_service_list_queued_owners (BusService *service,
1251                                 DBusList  **return_list,
1252                                 DBusError  *error)
1253 {
1254   DBusList *link;
1255
1256   _dbus_assert (*return_list == NULL);
1257
1258   link = _dbus_list_get_first_link (&service->owners);
1259   _dbus_assert (link != NULL);
1260   
1261   while (link != NULL)
1262     {
1263       BusOwner *owner;
1264       const char *uname;
1265
1266       owner = (BusOwner *) link->data;
1267       uname = bus_connection_get_name (owner->conn);
1268
1269       if (!_dbus_list_append (return_list, (char *)uname))
1270         goto oom;
1271
1272       link = _dbus_list_get_next_link (&service->owners, link);
1273     }
1274   
1275   return TRUE;
1276   
1277  oom:
1278   _dbus_list_clear (return_list);
1279   BUS_SET_OOM (error);
1280   return FALSE;
1281 }