2003-03-31 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / bus / connection.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* connection.c  Client connections
3  *
4  * Copyright (C) 2003  Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "connection.h"
24 #include "dispatch.h"
25 #include "loop.h"
26 #include "policy.h"
27 #include "services.h"
28 #include "utils.h"
29 #include <dbus/dbus-list.h>
30
31 static void bus_connection_remove_transactions (DBusConnection *connection);
32
33 struct BusConnections
34 {
35   int refcount;
36   DBusList *list; /**< List of all the connections */
37   BusContext *context;
38 };
39
40 static int connection_data_slot = -1;
41 static int connection_data_slot_refcount = 0;
42
43 typedef struct
44 {
45   BusConnections *connections;
46   DBusConnection *connection;
47   DBusList *services_owned;
48   char *name;
49   DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
50   DBusMessage *oom_message;
51   DBusPreallocatedSend *oom_preallocated;
52   unsigned long *group_ids;
53   int n_group_ids;
54   BusPolicy *policy;
55 } BusConnectionData;
56
57 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
58
59 static dbus_bool_t
60 connection_data_slot_ref (void)
61 {
62   if (connection_data_slot < 0)
63     {
64       connection_data_slot = dbus_connection_allocate_data_slot ();
65       
66       if (connection_data_slot < 0)
67         return FALSE;
68
69       _dbus_assert (connection_data_slot_refcount == 0);
70     }  
71
72   connection_data_slot_refcount += 1;
73
74   return TRUE;
75
76 }
77
78 static void
79 connection_data_slot_unref (void)
80 {
81   _dbus_assert (connection_data_slot_refcount > 0);
82
83   connection_data_slot_refcount -= 1;
84   
85   if (connection_data_slot_refcount == 0)
86     {
87       dbus_connection_free_data_slot (connection_data_slot);
88       connection_data_slot = -1;
89     }
90 }
91
92 void
93 bus_connection_disconnected (DBusConnection *connection)
94 {
95   BusConnectionData *d;
96   BusService *service;
97
98   d = BUS_CONNECTION_DATA (connection);
99   _dbus_assert (d != NULL);
100
101   _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
102                  d->name ? d->name : "(inactive)");
103   
104   /* Drop any service ownership. FIXME Unfortunately, this requires
105    * memory allocation and there doesn't seem to be a good way to
106    * handle it other than sleeping; we can't "fail" the operation of
107    * disconnecting a client, and preallocating a broadcast "service is
108    * now gone" message for every client-service pair seems kind of
109    * involved. Probably we need to do that though, and also
110    * extend BusTransaction to be able to revert generic
111    * stuff, not just sending a message (so we can e.g. revert
112    * removal of service owners).
113    */
114   while ((service = _dbus_list_get_last (&d->services_owned)))
115     {
116       BusTransaction *transaction;
117       DBusError error;
118
119     retry:
120       
121       dbus_error_init (&error);
122         
123       transaction = NULL;
124       while (transaction == NULL)
125         {
126           transaction = bus_transaction_new (d->connections->context);
127           bus_wait_for_memory ();
128         }
129         
130       if (!bus_service_remove_owner (service, connection,
131                                      transaction, &error))
132         {
133           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
134             {
135               dbus_error_free (&error);
136               bus_transaction_cancel_and_free (transaction);
137               bus_wait_for_memory ();
138               goto retry;
139             }
140           else
141             _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
142         }
143         
144       bus_transaction_execute_and_free (transaction);
145     }
146
147   bus_dispatch_remove_connection (connection);
148   
149   /* no more watching */
150   if (!dbus_connection_set_watch_functions (connection,
151                                             NULL, NULL, NULL,
152                                             connection,
153                                             NULL))
154     _dbus_assert_not_reached ("setting watch functions to NULL failed");
155
156   if (!dbus_connection_set_timeout_functions (connection,
157                                               NULL, NULL, NULL,
158                                               connection,
159                                               NULL))
160     _dbus_assert_not_reached ("setting timeout functions to NULL failed");
161   
162   dbus_connection_set_unix_user_function (connection,
163                                           NULL, NULL, NULL);
164   
165   bus_connection_remove_transactions (connection);
166
167   _dbus_list_remove (&d->connections->list, connection);
168
169   /* frees "d" as side effect */
170   dbus_connection_set_data (connection,
171                             connection_data_slot,
172                             NULL, NULL);
173
174   dbus_connection_unref (connection);
175 }
176
177 static dbus_bool_t
178 connection_watch_callback (DBusWatch     *watch,
179                            unsigned int   condition,
180                            void          *data)
181 {
182   DBusConnection *connection = data;
183   dbus_bool_t retval;
184
185   dbus_connection_ref (connection);
186   
187   retval = dbus_connection_handle_watch (connection, watch, condition);
188
189   bus_connection_dispatch_all_messages (connection);
190   
191   dbus_connection_unref (connection);
192
193   return retval;
194 }
195
196 static dbus_bool_t
197 add_connection_watch (DBusWatch      *watch,
198                       DBusConnection *connection)
199 {
200   return bus_loop_add_watch (watch, connection_watch_callback, connection,
201                              NULL);
202 }
203
204 static void
205 remove_connection_watch (DBusWatch      *watch,
206                          DBusConnection *connection)
207 {
208   bus_loop_remove_watch (watch, connection_watch_callback, connection);
209 }
210
211 static void
212 connection_timeout_callback (DBusTimeout   *timeout,
213                              void          *data)
214 {
215   DBusConnection *connection = data;
216
217   dbus_connection_ref (connection);
218
219   /* can return FALSE on OOM but we just let it fire again later */
220   dbus_timeout_handle (timeout);
221
222   bus_connection_dispatch_all_messages (connection);
223   
224   dbus_connection_unref (connection);
225 }
226
227 static dbus_bool_t
228 add_connection_timeout (DBusTimeout    *timeout,
229                         DBusConnection *connection)
230 {
231   return bus_loop_add_timeout (timeout, connection_timeout_callback, connection, NULL);
232 }
233
234 static void
235 remove_connection_timeout (DBusTimeout    *timeout,
236                            DBusConnection *connection)
237 {
238   bus_loop_remove_timeout (timeout, connection_timeout_callback, connection);
239 }
240
241 static dbus_bool_t
242 allow_user_function (DBusConnection *connection,
243                      unsigned long   uid,
244                      void           *data)
245 {
246   BusConnectionData *d;
247     
248   d = BUS_CONNECTION_DATA (connection);
249
250   _dbus_assert (d != NULL);
251
252   return TRUE; /* FIXME - this is just until we can parse a config file */
253   
254   return bus_context_allow_user (d->connections->context, uid);
255 }
256
257 static void
258 free_connection_data (void *data)
259 {
260   BusConnectionData *d = data;
261
262   /* services_owned should be NULL since we should be disconnected */
263   _dbus_assert (d->services_owned == NULL);
264   /* similarly */
265   _dbus_assert (d->transaction_messages == NULL);
266
267   if (d->oom_preallocated)
268     dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
269
270   if (d->oom_message)
271     dbus_message_unref (d->oom_message);
272
273   if (d->policy)
274     bus_policy_unref (d->policy);
275   
276   dbus_free (d->group_ids);
277   
278   dbus_free (d->name);
279   
280   dbus_free (d);
281 }
282
283 BusConnections*
284 bus_connections_new (BusContext *context)
285 {
286   BusConnections *connections;
287
288   if (!connection_data_slot_ref ())
289     return NULL;
290
291   connections = dbus_new0 (BusConnections, 1);
292   if (connections == NULL)
293     {
294       connection_data_slot_unref ();
295       return NULL;
296     }
297   
298   connections->refcount = 1;
299   connections->context = context;
300   
301   return connections;
302 }
303
304 void
305 bus_connections_ref (BusConnections *connections)
306 {
307   _dbus_assert (connections->refcount > 0);
308   connections->refcount += 1;
309 }
310
311 void
312 bus_connections_unref (BusConnections *connections)
313 {
314   _dbus_assert (connections->refcount > 0);
315   connections->refcount -= 1;
316   if (connections->refcount == 0)
317     {
318       while (connections->list != NULL)
319         {
320           DBusConnection *connection;
321
322           connection = connections->list->data;
323
324           dbus_connection_ref (connection);
325           dbus_connection_disconnect (connection);
326           bus_connection_disconnected (connection);
327           dbus_connection_unref (connection);
328         }
329       
330       _dbus_list_clear (&connections->list);
331       
332       dbus_free (connections);
333
334       connection_data_slot_unref ();
335     }
336 }
337
338 dbus_bool_t
339 bus_connections_setup_connection (BusConnections *connections,
340                                   DBusConnection *connection)
341 {
342   BusConnectionData *d;
343   dbus_bool_t retval;
344   
345   d = dbus_new0 (BusConnectionData, 1);
346   
347   if (d == NULL)
348     return FALSE;
349
350   d->connections = connections;
351   d->connection = connection;
352
353   _dbus_assert (connection_data_slot >= 0);
354   
355   if (!dbus_connection_set_data (connection,
356                                  connection_data_slot,
357                                  d, free_connection_data))
358     {
359       dbus_free (d);
360       return FALSE;
361     }
362
363   retval = FALSE;
364
365   d->n_group_ids = 0;
366   d->group_ids = NULL;
367   
368   if (!dbus_connection_set_watch_functions (connection,
369                                             (DBusAddWatchFunction) add_connection_watch,
370                                             (DBusRemoveWatchFunction) remove_connection_watch,
371                                             NULL,
372                                             connection,
373                                             NULL))
374     goto out;
375   
376   if (!dbus_connection_set_timeout_functions (connection,
377                                               (DBusAddTimeoutFunction) add_connection_timeout,
378                                               (DBusRemoveTimeoutFunction) remove_connection_timeout,
379                                               NULL,
380                                               connection, NULL))
381     goto out;
382
383
384   dbus_connection_set_unix_user_function (connection,
385                                           allow_user_function,
386                                           NULL, NULL);
387   
388   /* Setup the connection with the dispatcher */
389   if (!bus_dispatch_add_connection (connection))
390     goto out;
391   
392   if (!_dbus_list_append (&connections->list, connection))
393     {
394       bus_dispatch_remove_connection (connection);
395       goto out;
396     }
397   
398   dbus_connection_ref (connection);
399   retval = TRUE;
400
401  out:
402   if (!retval)
403     {
404       if (!dbus_connection_set_data (connection,
405                                      connection_data_slot,
406                                      NULL, NULL))
407         _dbus_assert_not_reached ("failed to set connection data to null");
408         
409       if (!dbus_connection_set_watch_functions (connection,
410                                                 NULL, NULL, NULL,
411                                                 connection,
412                                                 NULL))
413         _dbus_assert_not_reached ("setting watch functions to NULL failed");
414       
415       if (!dbus_connection_set_timeout_functions (connection,
416                                                   NULL, NULL, NULL,
417                                                   connection,
418                                                   NULL))
419         _dbus_assert_not_reached ("setting timeout functions to NULL failed");
420
421       dbus_connection_set_unix_user_function (connection,
422                                               NULL, NULL, NULL);
423     }
424   
425   return retval;
426 }
427
428 dbus_bool_t
429 bus_connection_get_groups  (DBusConnection       *connection,
430                             const unsigned long **groups,
431                             int                  *n_groups)
432 {
433   BusConnectionData *d;
434     
435   d = BUS_CONNECTION_DATA (connection);
436
437   _dbus_assert (d != NULL);
438
439   *groups = NULL;
440   *n_groups = 0;
441
442   /* we do a lazy lookup on groups a user is in for two reasons:
443    * 1) we can't do it on connection setup since the user
444    * hasn't authenticated and 2) it might be expensive
445    * and we don't need to do it if there are no group-based
446    * rules in the config file
447    */
448   
449   if (d->n_group_ids == 0)
450     {
451       unsigned long uid;
452       
453       if (dbus_connection_get_unix_user (connection, &uid))
454         {
455           if (!_dbus_get_groups (uid, &d->group_ids, &d->n_group_ids))
456             {
457               _dbus_verbose ("Did not get any groups for UID %lu\n",
458                              uid);
459               return FALSE;
460             }
461         }
462     }
463
464   *groups = d->group_ids;
465   *n_groups = d->n_group_ids;
466
467   return TRUE;
468 }
469
470 dbus_bool_t
471 bus_connection_is_in_group (DBusConnection *connection,
472                             unsigned long   gid)
473 {
474   int i;
475   const unsigned long *group_ids;
476   int n_group_ids;
477
478   if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids))
479     return FALSE;
480
481   i = 0;
482   while (i < n_group_ids)
483     {
484       if (group_ids[i] == gid)
485         return TRUE;
486       ++i;
487     }
488
489   return FALSE;
490 }
491
492 BusPolicy*
493 bus_connection_get_policy (DBusConnection *connection)
494 {
495   BusConnectionData *d;
496     
497   d = BUS_CONNECTION_DATA (connection);
498
499   _dbus_assert (d != NULL);
500
501   if (!dbus_connection_get_is_authenticated (connection))
502     {
503       _dbus_verbose ("Tried to get policy for unauthenticated connection!\n");
504       return NULL;
505     }
506   
507   /* We do lazy creation of the policy because
508    * it can only be done post-authentication.
509    */
510   if (d->policy == NULL)
511     {
512       d->policy =
513         bus_context_create_connection_policy (d->connections->context,
514                                               connection);
515
516       /* we may have a NULL policy on OOM or error getting list of
517        * groups for a user. In the latter case we don't handle it so
518        * well currently, just keep pretending we're out of memory,
519        * which is kind of bizarre.
520        */
521     }
522
523   return d->policy;
524 }
525
526 /**
527  * Calls function on each connection; if the function returns
528  * #FALSE, stops iterating.
529  *
530  * @param connections the connections object
531  * @param function the function
532  * @param data data to pass to it as a second arg
533  */
534 void
535 bus_connections_foreach (BusConnections               *connections,
536                          BusConnectionForeachFunction  function,
537                         void                          *data)
538 {
539   DBusList *link;
540   
541   link = _dbus_list_get_first_link (&connections->list);
542   while (link != NULL)
543     {
544       DBusConnection *connection = link->data;
545       DBusList *next = _dbus_list_get_next_link (&connections->list, link);
546
547       if (!(* function) (connection, data))
548         break;
549       
550       link = next;
551     }
552 }
553
554 BusContext*
555 bus_connections_get_context (BusConnections *connections)
556 {
557   return connections->context;
558 }
559
560 BusContext*
561 bus_connection_get_context (DBusConnection *connection)
562 {
563   BusConnectionData *d;
564
565   d = BUS_CONNECTION_DATA (connection);
566
567   _dbus_assert (d != NULL);
568
569   return d->connections->context;
570 }
571
572 BusConnections*
573 bus_connection_get_connections (DBusConnection *connection)
574 {
575   BusConnectionData *d;
576     
577   d = BUS_CONNECTION_DATA (connection);
578
579   _dbus_assert (d != NULL);
580
581   return d->connections;
582 }
583
584 BusRegistry*
585 bus_connection_get_registry (DBusConnection *connection)
586 {
587   BusConnectionData *d;
588
589   d = BUS_CONNECTION_DATA (connection);
590
591   _dbus_assert (d != NULL);
592
593   return bus_context_get_registry (d->connections->context);
594 }
595
596 BusActivation*
597 bus_connection_get_activation (DBusConnection *connection)
598 {
599   BusConnectionData *d;
600
601   d = BUS_CONNECTION_DATA (connection);
602
603   _dbus_assert (d != NULL);
604
605   return bus_context_get_activation (d->connections->context);
606 }
607
608 /**
609  * Checks whether the connection is registered with the message bus.
610  *
611  * @param connection the connection
612  * @returns #TRUE if we're an active message bus participant
613  */
614 dbus_bool_t
615 bus_connection_is_active (DBusConnection *connection)
616 {
617   BusConnectionData *d;
618
619   d = BUS_CONNECTION_DATA (connection);
620   
621   return d != NULL && d->name != NULL;
622 }
623
624 dbus_bool_t
625 bus_connection_preallocate_oom_error (DBusConnection *connection)
626 {
627   DBusMessage *message;
628   DBusPreallocatedSend *preallocated;
629   BusConnectionData *d;
630
631   d = BUS_CONNECTION_DATA (connection);  
632
633   _dbus_assert (d != NULL);
634
635   if (d->oom_preallocated != NULL)
636     return TRUE;
637   
638   preallocated = dbus_connection_preallocate_send (connection);
639   if (preallocated == NULL)
640     return FALSE;
641
642   /* d->name may be NULL, but that should be OK */
643   message = dbus_message_new (d->name,
644                               DBUS_ERROR_NO_MEMORY);
645   if (message == NULL)
646     {
647       dbus_connection_free_preallocated_send (connection, preallocated);
648       return FALSE;
649     }
650
651   dbus_message_set_is_error (message, TRUE);
652
653   if (!dbus_message_set_sender (message,
654                                 DBUS_SERVICE_DBUS))
655     {
656       dbus_connection_free_preallocated_send (connection, preallocated);
657       dbus_message_unref (message);
658       return FALSE;
659     }
660   
661   /* set reply serial to placeholder value just so space is already allocated
662    * for it.
663    */
664   if (!dbus_message_set_reply_serial (message, 14))
665     {
666       dbus_connection_free_preallocated_send (connection, preallocated);
667       dbus_message_unref (message);
668       return FALSE;
669     }
670
671   d->oom_message = message;
672   d->oom_preallocated = preallocated;
673   
674   return TRUE;
675 }
676
677 void
678 bus_connection_send_oom_error (DBusConnection *connection,
679                                DBusMessage    *in_reply_to)
680 {
681   BusConnectionData *d;
682
683   d = BUS_CONNECTION_DATA (connection);  
684
685   _dbus_assert (d != NULL);  
686   _dbus_assert (d->oom_message != NULL);
687
688   /* should always succeed since we set it to a placeholder earlier */
689   if (!dbus_message_set_reply_serial (d->oom_message,
690                                       dbus_message_get_serial (in_reply_to)))
691     _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
692
693   _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL);
694   
695   dbus_connection_send_preallocated (connection, d->oom_preallocated,
696                                      d->oom_message, NULL);
697
698   dbus_message_unref (d->oom_message);
699   d->oom_message = NULL;
700   d->oom_preallocated = NULL;
701 }
702
703 dbus_bool_t
704 bus_connection_add_owned_service (DBusConnection *connection,
705                                   BusService     *service)
706 {
707   BusConnectionData *d;
708
709   d = BUS_CONNECTION_DATA (connection);
710   _dbus_assert (d != NULL);
711
712   if (!_dbus_list_append (&d->services_owned,
713                           service))
714     return FALSE;
715
716   return TRUE;
717 }
718
719 void
720 bus_connection_remove_owned_service (DBusConnection *connection,
721                                      BusService     *service)
722 {
723   BusConnectionData *d;
724
725   d = BUS_CONNECTION_DATA (connection);
726   _dbus_assert (d != NULL);
727
728   _dbus_list_remove_last (&d->services_owned, service);
729 }
730
731 dbus_bool_t
732 bus_connection_set_name (DBusConnection   *connection,
733                          const DBusString *name)
734 {
735   BusConnectionData *d;
736   
737   d = BUS_CONNECTION_DATA (connection);
738   _dbus_assert (d != NULL);
739   _dbus_assert (d->name == NULL);
740
741   if (!_dbus_string_copy_data (name, &d->name))
742     return FALSE;
743
744   _dbus_assert (d->name != NULL);
745   
746   _dbus_verbose ("Name %s assigned to %p\n", d->name, connection);
747   
748   return TRUE;
749 }
750
751 const char *
752 bus_connection_get_name (DBusConnection *connection)
753 {
754   BusConnectionData *d;
755   
756   d = BUS_CONNECTION_DATA (connection);
757   _dbus_assert (d != NULL);
758   
759   return d->name;
760 }
761
762 typedef struct
763 {
764   BusTransaction *transaction;
765   DBusMessage    *message;
766   DBusPreallocatedSend *preallocated;
767 } MessageToSend;
768
769 struct BusTransaction
770 {
771   DBusList *connections;
772   BusContext *context;
773 };
774
775 static void
776 message_to_send_free (DBusConnection *connection,
777                       MessageToSend  *to_send)
778 {
779   if (to_send->message)
780     dbus_message_unref (to_send->message);
781
782   if (to_send->preallocated)
783     dbus_connection_free_preallocated_send (connection, to_send->preallocated);
784
785   dbus_free (to_send);
786 }
787
788 BusTransaction*
789 bus_transaction_new (BusContext *context)
790 {
791   BusTransaction *transaction;
792
793   transaction = dbus_new0 (BusTransaction, 1);
794   if (transaction == NULL)
795     return NULL;
796
797   transaction->context = context;
798   
799   return transaction;
800 }
801
802 BusContext*
803 bus_transaction_get_context (BusTransaction  *transaction)
804 {
805   return transaction->context;
806 }
807
808 BusConnections*
809 bus_transaction_get_connections (BusTransaction  *transaction)
810 {
811   return bus_context_get_connections (transaction->context);
812 }
813
814 dbus_bool_t
815 bus_transaction_send_message (BusTransaction *transaction,
816                               DBusConnection *connection,
817                               DBusMessage    *message)
818 {
819   MessageToSend *to_send;
820   BusConnectionData *d;
821   DBusList *link;
822
823   _dbus_verbose ("  trying to add message %s to transaction%s\n",
824                  dbus_message_get_name (message),
825                  dbus_connection_get_is_connected (connection) ?
826                  "" : " (disconnected)");
827
828   _dbus_assert (dbus_message_get_sender (message) != NULL);
829   
830   if (!dbus_connection_get_is_connected (connection))
831     return TRUE; /* silently ignore disconnected connections */
832   
833   d = BUS_CONNECTION_DATA (connection);
834   _dbus_assert (d != NULL);
835   
836   to_send = dbus_new (MessageToSend, 1);
837   if (to_send == NULL)
838     {
839       return FALSE;
840     }
841
842   to_send->preallocated = dbus_connection_preallocate_send (connection);
843   if (to_send->preallocated == NULL)
844     {
845       dbus_free (to_send);
846       return FALSE;
847     }  
848   
849   dbus_message_ref (message);
850   to_send->message = message;
851   to_send->transaction = transaction;
852
853   _dbus_verbose ("about to prepend message\n");
854   
855   if (!_dbus_list_prepend (&d->transaction_messages, to_send))
856     {
857       message_to_send_free (connection, to_send);
858       return FALSE;
859     }
860
861   _dbus_verbose ("prepended message\n");
862   
863   /* See if we already had this connection in the list
864    * for this transaction. If we have a pending message,
865    * then we should already be in transaction->connections
866    */
867   link = _dbus_list_get_first_link (&d->transaction_messages);
868   _dbus_assert (link->data == to_send);
869   link = _dbus_list_get_next_link (&d->transaction_messages, link);
870   while (link != NULL)
871     {
872       MessageToSend *m = link->data;
873       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
874       
875       if (m->transaction == transaction)
876         break;
877         
878       link = next;
879     }
880
881   if (link == NULL)
882     {
883       if (!_dbus_list_prepend (&transaction->connections, connection))
884         {
885           _dbus_list_remove (&d->transaction_messages, to_send);
886           message_to_send_free (connection, to_send);
887           return FALSE;
888         }
889     }
890
891   return TRUE;
892 }
893
894 static void
895 connection_cancel_transaction (DBusConnection *connection,
896                                BusTransaction *transaction)
897 {
898   DBusList *link;
899   BusConnectionData *d;
900   
901   d = BUS_CONNECTION_DATA (connection);
902   _dbus_assert (d != NULL);
903   
904   link = _dbus_list_get_first_link (&d->transaction_messages);
905   while (link != NULL)
906     {
907       MessageToSend *m = link->data;
908       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
909       
910       if (m->transaction == transaction)
911         {
912           _dbus_list_remove_link (&d->transaction_messages,
913                                   link);
914           
915           message_to_send_free (connection, m);
916         }
917         
918       link = next;
919     }
920 }
921
922 void
923 bus_transaction_cancel_and_free (BusTransaction *transaction)
924 {
925   DBusConnection *connection;
926
927   _dbus_verbose ("TRANSACTION: cancelled\n");
928   
929   while ((connection = _dbus_list_pop_first (&transaction->connections)))
930     connection_cancel_transaction (connection, transaction);
931
932   _dbus_assert (transaction->connections == NULL);
933
934   dbus_free (transaction);
935 }
936
937 static void
938 connection_execute_transaction (DBusConnection *connection,
939                                 BusTransaction *transaction)
940 {
941   DBusList *link;
942   BusConnectionData *d;
943   
944   d = BUS_CONNECTION_DATA (connection);
945   _dbus_assert (d != NULL);
946
947   /* Send the queue in order (FIFO) */
948   link = _dbus_list_get_last_link (&d->transaction_messages);
949   while (link != NULL)
950     {
951       MessageToSend *m = link->data;
952       DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
953       
954       if (m->transaction == transaction)
955         {
956           _dbus_list_remove_link (&d->transaction_messages,
957                                   link);
958
959           _dbus_assert (dbus_message_get_sender (m->message) != NULL);
960           
961           dbus_connection_send_preallocated (connection,
962                                              m->preallocated,
963                                              m->message,
964                                              NULL);
965
966           m->preallocated = NULL; /* so we don't double-free it */
967           
968           message_to_send_free (connection, m);
969         }
970         
971       link = prev;
972     }
973 }
974
975 void
976 bus_transaction_execute_and_free (BusTransaction *transaction)
977 {
978   /* For each connection in transaction->connections
979    * send the messages
980    */
981   DBusConnection *connection;
982
983   _dbus_verbose ("TRANSACTION: executing\n");
984   
985   while ((connection = _dbus_list_pop_first (&transaction->connections)))
986     connection_execute_transaction (connection, transaction);
987
988   _dbus_assert (transaction->connections == NULL);
989
990   dbus_free (transaction);
991 }
992
993 static void
994 bus_connection_remove_transactions (DBusConnection *connection)
995 {
996   MessageToSend *to_send;
997   BusConnectionData *d;
998   
999   d = BUS_CONNECTION_DATA (connection);
1000   _dbus_assert (d != NULL);
1001   
1002   while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
1003     {
1004       /* only has an effect for the first MessageToSend listing this transaction */
1005       _dbus_list_remove (&to_send->transaction->connections,
1006                          connection);
1007
1008       _dbus_list_remove (&d->transaction_messages, to_send);
1009       message_to_send_free (connection, to_send);
1010     }
1011 }
1012
1013 /**
1014  * Converts the DBusError to a message reply
1015  */
1016 dbus_bool_t
1017 bus_transaction_send_error_reply (BusTransaction  *transaction,
1018                                   DBusConnection  *connection,
1019                                   const DBusError *error,
1020                                   DBusMessage     *in_reply_to)
1021 {
1022   DBusMessage *reply;
1023   
1024   _dbus_assert (error != NULL);
1025   _DBUS_ASSERT_ERROR_IS_SET (error);
1026   
1027   reply = dbus_message_new_error_reply (in_reply_to,
1028                                         error->name,
1029                                         error->message);
1030   if (reply == NULL)
1031     return FALSE;
1032
1033   if (!bus_transaction_send_message (transaction, connection, reply))
1034     {
1035       dbus_message_unref (reply);
1036       return FALSE;
1037     }
1038
1039   return TRUE;
1040 }