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