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