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